Episode ini membedah request lifecycle: nilai request-scoped lewat context, pembatalan request, dan middleware.Timeout untuk membatasi durasi. Kalian juga belajar memakai goroutine di handler, middleware.Throttle untuk membatasi konkurensi, serta sinkronisasi akses terhadap state bersama.

Go adalah bahasa yang dibangun untuk konkurensi, dan net/http menjalankan setiap request dalam goroutine sendiri. Episode 12 mengajarkan cara memakai kekuatan itu dengan aman: membawa data antar lapisan lewat context, membatasi waktu eksekusi, dan mengatur beban konkurensi.
Tanpa pemahaman ini, handler bisa menghabiskan resource tanpa batas, state bersama bisa diakses bersamaan secara tidak aman, dan request yang sudah dibatalkan klien tetap memakan kerja server.
Context cocok untuk data yang melekat pada satu request — user ID, request ID, role:
type userKey struct{}
ctx := context.WithValue(req.Context(), userKey{}, user)
next.ServeHTTP(w, req.WithContext(ctx))context.WithValue(req.Context(), userKey{}, user) menempelkan nilai ke context, lalu req.WithContext(ctx) membawa context baru bersama request. Tipe key userKey (struct kosong) mencegah tabrakan dengan key package lain.
func currentUser(req *http.Request) (User, bool) {
u, ok := req.Context().Value(userKey{}).(User)
return u, ok
}req.Context().Value(userKey{}) mengambil nilai yang disimpan. Type assertion memastikan nilai bertipe User — jika tidak ada atau salah tipe, dikembalikan false.
Context request dibatalkan otomatis saat klien memutus koneksi. Semua operasi yang menerima context — database, HTTP client, channel select — ikut berhenti:
func handleSlow(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
select {
case result := <-compute(ctx):
writeJSON(w, http.StatusOK, result)
case <-ctx.Done():
return
}
}<-ctx.Done() memberi tahu goroutine bahwa request sudah tidak relevan. Handler langsung kembali tanpa menulis respons — menghemat kerja yang sia-sia.
Jangan biarkan handler berjalan selamanya:
r.Use(middleware.Timeout(5 * time.Second))middleware.Timeout(5 * time.Second) membungkus handler dengan context yang dibatalkan setelah 5 detik. Handler yang melampaui batas akan berhenti pada checkpoint ctx.Done() berikutnya, dan respons default dikirim.
Timeout middleware berfungsi karena menginjeksi context berbatas waktu ke request. Itulah mengapa handler wajib meneruskan req.Context() ke semua operasi — jika context diabaikan, timeout tidak akan pernah dipicu.
Beban berat bisa dipecah ke goroutine untuk mempercepat respons:
r.Get("/dashboard", func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
userCh := make(chan User)
statCh := make(chan Stats)
go func() {
userCh <- userRepo.FindByID(ctx, userID)
}()
go func() {
statCh <- statsRepo.Load(ctx)
}()
user := <-userCh
stats := <-statCh
writeJSON(w, http.StatusOK, map[string]any{
"user": user,
"stats": stats,
})
})Kedua query berjalan paralel di goroutine, sehingga total waktu hanya sebesar query paling lambat, bukan penjumlahan keduanya. <-userCh menunggu hasil dari masing-masing channel.
http.ResponseWriter dari goroutine lain.sync.WaitGroup.middleware.Throttle membatasi jumlah request bersamaan:
r.Use(middleware.Throttle(50))middleware.Throttle(50) menolak request yang melebihi 50 request berjalan bersamaan — melindungi server dari lonjakan beban. Untuk antrian dengan buffer, gunakan middleware.ThrottleBacklog.
Saat beberapa goroutine memakai data yang sama, lindungi dengan mutex:
type Counter struct {
mu sync.Mutex
visits int
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.visits++
}c.mu.Lock() memastikan hanya satu goroutine yang mengubah visits pada satu waktu. Tanpa mutex, dua request bersamaan bisa saling menimpa nilai.
Inti yang harus dibawa pulang:
ctx.Done() untuk pembatalan request dari klien.middleware.Timeout membatasi durasi eksekusi per request.middleware.Throttle membatasi konkurensi maksimal.sync.Mutex.Di episode 13 selanjutnya kita mengamankan akses: autentikasi dan otorisasi — JWT dengan golang-jwt sebagai middleware, BasicAuth bawaan, session cookie dan refresh token, RBAC middleware, serta integrasi OAuth2 dan OpenID Connect dengan Keycloak.