Akar Masalah: Bottleneck Sekuensial pada Test Suite
Pertumbuhan basis kode berbanding lurus dengan jumlah pengujian otomatis. Pada test suite berskala besar—khususnya integrasi dan End-to-End (E2E)—eksekusi sekuensial dalam satu runner CI menjadi titik hambat utama. Runner tunggal memiliki batas kapasitas CPU dan memori, sehingga penambahan spesifikasi mesin vertikal (vertical scaling) cepat menemui batas efisiensi biaya.
Dampaknya langsung terasa pada siklus rilis: durasi pipeline meningkat dari hitungan menit menjadi puluhan menit, antrean pull request menumpuk, dan developer feedback loop melambat signifikan. Solusi horizontal untuk masalah ini adalah test sharding: memecah kumpulan pengujian ke dalam beberapa subset independen (shard) dan mengeksekusinya secara paralel di beberapa runner GitHub Actions.
Arsitektur Test Sharding dan Matrix Strategy
Test sharding membagi daftar file atau fungsi tes berdasarkan indeks pecahan dari total partisi yang ditentukan (format index/total). Agar eksekusi stabil, pembagian beban kerja harus bersifat deterministik. Test runner seperti Playwright atau Vitest menggunakan algoritma hashing pada path file pengujian untuk memetakan file secara konsisten ke shard tertentu.
Di GitHub Actions, orkestrasi ini ditangani melalui strategy.matrix. Matrix membangkitkan sekumpulan job identik yang berjalan paralel, masing-masing membawa variabel lingkungan penanda indeks shard unik.
+-----------------------------------------------------------------+
| GitHub Actions Runner |
| |
| +------------------+ +------------------+ +-------------+ |
| | Shard Job 1/4 | | Shard Job 2/4 | | Shard 3 & 4 | |
| | (Tests A - G) | | (Tests H - N) | | (...) | |
| +--------+---------+ +--------+---------+ +------+------+ |
| | | | |
| v v v |
| [Blob Report 1] [Blob Report 2] [Blob Rep. 3-4] |
+------------+---------------------+-------------------+----------+
| | |
+-------------------->|<------------------+
v
+-----------------------------------------+
| Downstream Consolidation |
| 1. Download all shard artifacts |
| 2. Merge reports (HTML/JUnit) |
| 3. Combine LCOV/Coverage data |
+-----------------------------------------+Implementasi Workflow Paralel (Contoh: Playwright)
Konfigurasi berikut mendistribusikan eksekusi Playwright ke dalam 4 shard paralel menggunakan matrix, menyimpan output laporan modular, lalu menggabungkannya dalam downstream job terpisah.
name: E2E Tests
on:
pull_request:
branches: [main]
jobs:
test-sharding:
name: Run Shard ${{ matrix.shardIndex }} of ${{ matrix.shardTotal }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium
- name: Run tests on shard
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
PLAYWRIGHT_BLOB_OUTPUT_NAME: blob-report-${{ matrix.shardIndex }}
- name: Upload blob report artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report/
retention-days: 1Konsolidasi Hasil: Merging Report dan Coverage
Menjalankan tes secara terpisah menghasilkan output terfragmentasi. Hasil audit dan pelaporan harus disatukan agar tim pengembang tetap mendapatkan satu dashboard ringkasan eksekusi.
1. Merge Test Report
Gunakan downstream job dengan dependensi needs: [test-sharding] untuk mengunduh seluruh artifak dan memicu perintah penggabungan bawaan runner.
merge-reports:
name: Merge Reports & Publish
if: always()
needs: [test-sharding]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Download all shard reports
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- name: Merge into single HTML Report
run: npx playwright merge-reports --reporter html ./all-blob-reports
- name: Upload Consolidated Report
uses: actions/upload-artifact@v4
with:
name: playwright-report-final
path: playwright-report/
retention-days: 72. Konsolidasi Coverage Data
Untuk unit test (misal Vitest atau Jest), tiap shard menghasilkan file coverage-final.json atau file .lcov. Pada downstream job yang sama, gabungkan seluruh file tersebut menggunakan tool CLI seperti nyc:
npx nyc merge ./all-coverage-artifacts ./coverage/merged-coverage.json
npx nyc report --reporter=lcov --reporter=text --temp-dir=./coverageAnalisis Trade-Off: Menit CI vs Developer Wait Time
Sharding memangkas wall-clock time (waktu tunggu nyata), tetapi berpotensi meningkatkan total konsumsi menit penagihan (billable minutes) akibat overhead komputasi berulang.
Rumus Total Durasi Mesin:Total Machine Minutes = N × (Setup Overhead) + Total Raw Test Time
Di mana N adalah jumlah shard.
Setiap runner baru memerlukan fase checkout, instalasi Node.js, dependensi npm ci, dan setup runtime browser. Jika fase setup memakan waktu 2 menit dan test suite dibagi ke dalam 4 runner, terjadi penambahan beban statis sebesar 8 menit komputasi (4 runner × 2 menit).
- Kapan Menguntungkan: Test suite berdurasi 30 menit dibagi ke 4 shard (masing-masing 7.5 menit tes + 2 menit setup = ~9.5 menit total waktu tunggu). Developer menghemat ~20 menit waktu tunggu per PR, sebanding dengan sedikit kenaikan billable minutes.
- Kapan Merugikan: Test suite hanya berdurasi 3 menit lalu dibagi ke 6 shard. Durasi setup mendominasi siklus eksekusi runner, memboroskan kuota penagihan GitHub Actions tanpa perolehan kecepatan yang signifikan.
Checklist Kelayakan Penerapan Sharding
Evaluasi kondisi test suite sebelum menerapkan sharding pada pipeline produksi:
- Isolasi Test Suite: Setiap test case harus stateless. Uji coba tidak boleh bergantung pada mutable state bersama, database global yang tidak diisolasi, atau urutan eksekusi antar-file.
- Rasio Waktu Setup terhadap Eksekusi: Total waktu tes murni minimal harus 3 kali lebih besar daripada waktu setup lingkungan (checkout + install runtime + dependensi).
- Deterministik: Tidak ada flaky test akibat kompetisi network resource ketika beberapa shard mengakses API staging/mock secara bersamaan.
- Kuota Concurrency Runner: Pastikan kuota concurrent jobs pada akun atau organisasi GitHub mencukupi agar runner shard tidak masuk antrean tunggu (queued state) yang justru memperlambat pipeline.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!