Context
Memahami package context di Go β cara mengelola deadline, sinyal cancelllation, dan data berbasis request.
Versi Bahasa Indonesia. Baca dalam Bahasa Inggris
Package context di Go menyediakan cara untuk mengelola data berbasis request, deadline, dan sinyal pembatalan (cancellation) melintasi batas API dan antar proses.
Ini wajib dipahami jika Anda ingin membangun aplikasi production-ready yang robust di Go, terutama untuk menangani workload konkuren seperti HTTP server, query database, dan task latar belakang.
Request masuk ke server harus membuat Context, dan panggilan keluar ke server lain harus menerima Context. Rantai fungsi di antaranya harus menyebarkan (propagate) Context, opsional menggantinya dengan Context turunan yang dibuat menggunakan WithCancel, WithDeadline, WithTimeout, atau WithValue. Ketika suatu Context dibatalkan, semua Context turunannya juga ikut dibatalkan.
Context
context.Context
Interface dasar yang menyediakan method untuk mengambil deadline, sinyal pembatalan, dan nilai.
Done() <-chan struct{}: Mengembalikan channel yang tertutup ketika context dibatalkan atau timeout.Err() error: Mengembalikan alasan pembatalan, jika ada.Deadline() (time.Time, bool): Mengembalikan deadline dan apakah deadline ditetapkan.Value(key any) any: Mengambil nilai berbasis request.
Fungsi dalam Package context
context.WithCancel
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)Mengembalikan salinan parent context yang dapat dibatalkan secara manual dengan memanggil fungsi cancel yang dikembalikan.
context.WithDeadline
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)Mengembalikan salinan parent context yang otomatis dibatalkan setelah deadline terlampaui.
context.WithTimeout
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)Mengembalikan salinan parent context yang otomatis dibatalkan setelah durasi tertentu. WithTimeout setara dengan WithDeadline(parent, time.Now().Add(timeout)).
context.WithValue
func WithValue(parent Context, key, val any) ContextMengembalikan salinan parent context yang membawa nilai berbasis request.
Best Practices
- Pass Context Secara Eksplisit:
- Selalu berikan
context.Contextsebagai argumen pertama pada fungsi yang menangani operasi yang mungkin memerlukan pembatalan atau deadline. - Gunakan context untuk menyebarkan metadata request (misalnya trace ID) melintasi HTTP handler atau gRPC interceptor.
- Kombinasikan context secara tepat untuk menyebarkan pembatalan atau deadline.
- Selalu berikan
- Hormati Pembatalan:
-
Periksa
ctx.Done()secara periodik dalam operasi jangka panjang dan keluar segera saat dibatalkan.select { case <-ctx.Done(): return ctx.Err() default: // Lanjutkan pemrosesan }
-
- Gunakan Timeout Secukupnya:
- Hindari penggunaan
context.WithTimeoutberlebihan dalam operasi bersarang untuk mencegah deadline yang saling bertentangan. Tetapkan timeout di level yang lebih tinggi dan propagasikan ke bawah.
- Hindari penggunaan
- Hindari:
- Menggunakan context.WithValue untuk Data Kritis: Gunakan
WithValuehanya untuk data berbasis request. Hindari menyimpan data kritis atau besar; sebaliknya, berikan data tersebut secara eksplisit. - Menggunakan
context.BackgroundDi Mana Saja: Gunakancontext.Backgroundhanya untuk operasi root-level (misalnya di main atau test). - Mutasi Nilai dalam Context: Context bersifat immutable. Hindari mencoba memodifikasi atau mengganti nilai dalam context.
- Menggunakan context.WithValue untuk Data Kritis: Gunakan
Contoh
package main
import (
"context"
"net/http"
"time"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
defer cancel()
err := doWork(ctx)
if err != nil {
http.Error(w, "Request timed out", http.StatusRequestTimeout)
return
}
w.Write([]byte("Success"))
})
http.ListenAndServe(":8080", nil)
}
func doWork(ctx context.Context) error {
select {
case <-time.After(3 * time.Second): // Simulasi kerja lama
return nil
case <-ctx.Done():
return ctx.Err()
}
}- Pada contoh di atas kami mencoba mensimulasikan kerja lama dan seharusnya merespons dengan error
Request timed out. - Coba buat timeout lebih lama dan lihat hasilnya.
Referensi
Last updated on