Merancang konfigurasi load test yang matang: stages ramping, threshold lanjutan, area ext, dan environment variables lewat __ENV agar skrip yang sama berjalan berbeda untuk lingkungan local, staging, dan menyerupai produksi.

Di episode 6 kalian merapikan skrip menjadi modul-modul yang bisa dipakai ulang — helper request, modul auth, dan buildOptions() yang menyatukan threshold. Namun ada satu kenyataan yang belum kita hadapi: angka-angka seperti vus: 10 dan duration: "30s" masih membeku di dalam kode. Skrip yang sama dipakai untuk local, staging, dan lingkungan menyerupai produksi — padahal kebutuhannya sangat berbeda.
Episode ini menjawab pertanyaan yang menentukan kualitas load test skala tim: bagaimana mengonfigurasi test tanpa mengubah kode? Kita akan membedah opsi-opsi canggih — stages (ramping), thresholds lanjutan, dan area ext — lalu menghubungkannya dengan environment variables lewat __ENV. Di akhir episode, satu skrip k6 yang sama bisa berjalan sebagai smoke test di laptop, load test penuh di staging, dan soak singkat di lingkungan produksi — hanya dengan berpindah perintah, bukan berpindah file.
Bayangkan mengubah beban test setiap kali ingin mencoba skenario baru: buka file, edit vus, simpan, jalankan, ulangi. Dua masalah muncul. Pertama, kode dan konfigurasi tercampur — perubahan "berapa beban" jadi satu dengan perubahan "bagaimana skrip bekerja", menyulitkan review dan memicu kesalahan. Kedua, satu lingkungan tidak cocok untuk semua — beban 200 VU yang wajar untuk staging adalah serangan brutal untuk laptop pengembang.
Prinsipnya sederhana: skrip adalah kode, beban dan lingkungan adalah konfigurasi. Skrip ditulis sekali, dikelola di version control; beban dan target URL disuntikkan saat eksekusi. Inilah yang membuka pintu ke CI/CD yang kita bahas di episode 16 nanti.
vus dan duration menghasilkan beban yang konstan — 20 pengguna menekan server dengan ritme yang sama selama 30 detik. Beban seperti itu jarang terjadi di dunia nyata. Pengguna datang bertahap, ramai di jam tertentu, lalu pergi. stages merekam rencana itu sebagai daftar langkah:
export const options = {
stages: [
{ duration: "1m", target: 20 },
{ duration: "2m", target: 50 },
{ duration: "3m", target: 50 },
{ duration: "1m", target: 0 },
],
};Setiap langkah menyatakan: dalam duration ini, naikkan (atau turunkan) jumlah VU hingga mencapai target. Di atas, beban naik dari 0 ke 20 di menit pertama, merangkak ke 50 di dua menit berikutnya, stabil lima menit, lalu melandai kembali ke nol. Bentuk ini disebut ramping — dan ia menjawab pertanyaan yang tidak bisa dijawab beban konstan: pada titik berapa server mulai menyerah?
Ramping juga melindungi server dari cold start yang tidak realistis. Bayangkan menguji cache yang masih kosong: 500 VU tiba-tiba menyerbu cache dingin akan melaporkan latensi tinggi yang salah. Dengan ramp up, cache sempat terisi dan pengukuran mencerminkan kondisi operasional, bukan kondisi awal.
Perlu diingat dari episode 2: stages tidak bisa digabung dengan vus dan duration dalam satu skrip — k6 menolak kombinasi ini. Pilih salah satu model.
Episode 4 memperkenalkan threshold dasar berbentuk string. Untuk kebutuhan produksi, threshold bisa berupa array dengan beberapa aturan dan mode abortOnFail — hentikan test segera ketika ambang dilanggar, alih-alih menunggu selesai:
export const options = {
thresholds: {
http_req_duration: [
{ threshold: "p(95)<500", abortOnFail: true },
"p(99)<1000",
],
http_req_failed: ["rate<0.01"],
},
};Membaca ini: 95% request harus selesai di bawah 500 ms dan bila dilanggar test berhenti segera (abortOnFail); 99% request di bawah 1000 ms; dan rasio request gagal di bawah 1%. abortOnFail sangat berharga di CI — alih-alih membuang waktu menjalankan beban 10 menit yang jelas-jelas sudah melewati ambang, pipeline gagal di menit ketiga dan tim bisa menginvestigasi lebih cepat.
Kombinasikan dengan gracefulStop untuk memberi waktu jeda, dan catat bahwa setiap threshold yang dilanggar membuat k6 keluar dengan exit code 99 — bahasa sukses-gagal yang dipahami semua pipeline.
Opsi ext adalah ruang cadangan di options untuk tool dan ekstensi pihak ketiga menaruh konfigurasinya. Contoh klasik adalah runner k6 Cloud yang membaca identitas project dan nama test dari sana:
export const options = {
vus: 10,
duration: "30s",
ext: {
loadimpact: {
projectID: 12345,
name: "belajar-k6-staging",
},
},
};ext tidak mengubah perilaku eksekusi lokal sama sekali — ia hanya dibaca oleh layanan atau ekstensi yang memahami strukturnya. Gunakan area ini hanya untuk keperluan yang memang spesifik pihak ketiga; konfigurasi yang kalian kendalikan sendiri lebih tepat diletakkan di skrip atau __ENV. (Perlu dicatat: untuk Grafana Cloud, alur modern lebih sering memakai flag CLI k6 cloud run daripada menaruh konfigurasi di ext.)
Inilah pahlawan episode ini. k6 membuka akses ke environment variables lewat objek global __ENV — nilainya bisa disuntikkan saat menjalankan test dengan flag -e:
const BASE_URL = __ENV.BASE_URL || "https://api.example.com";
const VUS = Number(__ENV.VUS) || 10;
export const options = {
vus: VUS,
duration: __ENV.DURATION || "30s",
};Lalu jalankan dengan parameter runtime:
k6 run -e BASE_URL=https://staging.example.com -e VUS=50 -e DURATION=5m script.jsDua hal yang wajib diingat tentang __ENV:
__ENV adalah string. Beban numerik wajib diubah dengan Number(__ENV.VUS) — jika tidak, vus bernilai string dan k6 menolak dengan error.|| memastikan skrip tetap bisa dijalankan tanpa argumen apa pun. Skrip yang aman adalah skrip yang bisa dijalankan polos dan bisa diparameterisasi.Ingat pola buildOptions dari episode 6? Sekarang kekuatannya terasa. buildOptions bisa membaca __ENV, sehingga satu fungsi menghasilkan varian options yang berbeda per lingkungan.
Praktik terbaik yang menyatukan semuanya: definisikan profil lingkungan dalam satu modul konfigurasi, dan pilih profil lewat __ENV.ENV:
const profiles = {
local: { baseUrl: "http://localhost:3000", vus: 5, duration: "1m" },
staging: { baseUrl: "https://staging.example.com", vus: 50, duration: "5m" },
production: { baseUrl: "https://api.example.com", vus: 200, duration: "10m" },
};
export function currentProfile() {
return profiles[__ENV.ENV] || profiles.local;
}Dan main.js tinggal membaca profil itu:
import { currentProfile } from "./config.js";
const profile = currentProfile();
export const options = {
vus: profile.vus,
duration: profile.duration,
thresholds: {
http_req_duration: ["p(95)<500"],
},
};
export default function () {
console.log(`Menguji ${profile.baseUrl} dengan ${profile.vus} VU`);
}Menjalankan test untuk tiap lingkungan kini tinggal satu baris — dan tidak ada satu pun nilai lingkungan yang bocor ke dalam kode:
k6 run -e ENV=local script.js
k6 run -e ENV=staging script.js
k6 run -e ENV=production script.jsPerhatikan bahwa skrip yang sama berjalan di ketiga lingkungan. Ini bukan sekadar kenyamanan — ini konsistensi: test yang kalian jalankan di laptop adalah test yang sama yang dijalankan di pipeline. Perbedaannya hanya konfigurasi.
Important
Saat memilih profil produksi, dua pertimbangan wajib ada: izin dan threshold. Pastikan load test terhadap lingkungan produksi dijadwalkan dengan persetujuan pemilik layanan, dan threshold untuk lingkungan lambat tidak disalin mentah dari staging — profil produksi yang menyalin threshold staging hanya akan memproduksi false alarm.
Number() pada __ENV numerik. Semua env var adalah string; vus dan nilai metrik yang lolos sebagai string akan membuat k6 menolak atau menghitung salah.stages dengan vus dan duration. k6 menolak kombinasi ini. Pilih salah satu model beban.-e untuk test produksi. Token dan kredensial tetap rahasia — injeksikan lewat secret manager di CI, bukan hardcode di perintah.Di episode 7 ini kalian telah mengubah skrip k6 dari program menjadi alat:
abortOnFail untuk kegagalan cepat, dan exit code 99 untuk pipeline.ext: ruang konfigurasi khusus tool pihak ketiga.__ENV: parameter runtime lewat -e, dengan default yang aman.Jalankan skrip profil ini dengan k6 run -e ENV=staging main.js dan bandingkan hasilnya dengan versi local. Sekarang skrip kalian bisa dijalankan di lingkungan mana pun — tapi ada satu hal yang masih membuatnya kurang realistis: data yang dipakai masih hardcode di dalam skrip. Di episode 8 kita membuka data — Data Driven Testing dan Ketersediaan Data: membaca data dari CSV dan JSON, merandomisasi input dengan randomItem, dan menjaga kebersihan data agar test tetap bisa diulang. Sampai jumpa di episode 8!