Pelajaran modul (5/5)
`context.Context`: pembatalan dan tenggat waktu
Paket context adalah standar de-facto untuk propagasi
pembatalan, tenggat waktu, dan nilai yang terikat cakupan di sepanjang rantai panggilan,
di beberapa goroutine. Semua paket "jaringan" standar
(net/http, database/sql, os/exec) menerima context.Context sebagai
parameter pertama mereka.
Antarmuka
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key any) any
}Done(): saluran yang ditutup ketika konteksnya dibatalkan.Err(): alasan pembatalan (context.Canceledataucontext.DeadlineExceeded).Deadline(): batas waktu opsional.Value(): pencarian nilai yang terikat cakupan (gunakan dengan hemat).
Empat fungsi dasar
ctx := context.Background() // radice: usalo in main, init, test
ctx := context.TODO() // "non so ancora": stub esplicito
ctx, cancel := context.WithCancel(parent) // cancel manuale
ctx, cancel := context.WithTimeout(parent, d) // scadenza relativa
ctx, cancel := context.WithDeadline(parent, t) // scadenza assoluta
ctx := context.WithValue(parent, key, value) // valore scope-boundSemua formulir turunan mengembalikan fungsi cancel: selalu panggil saja
(idealnya dengan defer) untuk melepaskan sumber daya internal, meskipun
konteksnya sudah habis masa berlakunya.
Pola batas waktu
func fetchUser(id string) (*User, error) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
return queryUser(ctx, id) // queryUser deve rispettare ctx
}Jika queryUser membutuhkan waktu lebih dari 2 detik, ctx.Done() ditutup dan
fungsi tersebut harus membatalkan operasi.
Menghargai konteks: pilih pada Selesai()
func slowWork(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return ctx.Err() // canceled o deadline exceeded
case <-time.After(100 * time.Millisecond):
// un tick di lavoro
}
}
}Aturannya: di mana pun fungsi Anda mungkin diblokir untuk waktu yang lama, itu akan terjadi harus menangani ctx.Selesai(). Kalau tidak, konteksnya adalah "dinyalakan" untuk tidak ada apa-apa.
Konvensi parameter pertama
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
// ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionalectxSELALU sebagai parameter pertama, bernamactx.- Jangan pernah memasukkan
Contextsebagai bidang struct (pengecualian yang sangat jarang terjadi). - Jangan pernah melewati
nil: gunakancontext.TODO()sebagai stub.
konteks.WithValue: hemat
type userKey struct{}
ctx := context.WithValue(ctx, userKey{}, currentUser)
// più sotto:
if u, ok := ctx.Value(userKey{}).(*User); ok { ... }Pedoman:
- HANYA untuk data cakupan permintaan (ID permintaan, ID jejak, identitas pengguna).
- JANGAN PERNAH untuk parameter fungsi: teruskan secara normal.
- Kunci jenis kustom yang tidak diekspor untuk menghindari tabrakan.
Propagasi sepanjang rantai
func handleHTTP(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() // context legato al ciclo di vita della richiesta
user, err := fetchUser(ctx, r.URL.Query().Get("id"))
if err != nil { ... }
// ...
}net/http secara otomatis membatalkan r.Context() saat klien
terputus atau ketika pawang kembali. Dengan menyebarkannya ke semua orang
panggilan hilir, seluruh pohon operasi dibatalkan
cascade: tidak ada pekerjaan yang sia-sia setelah terputus.
Cobalah
Buat konteks dengan batas waktu 1 detik yang berasal dari konteks.Background() dan ingatlah untuk memanggil pembatalan dengan penundaan.
Tunjukkan petunjuk
`context.WithTimeout(parent, d)` mengembalikan `(ctx, cancel)`; selalu menelepon batal.
Solusi tersedia setelah 3 upaya
Gunakan <-ctx.Done() dalam pilihan untuk menunggu konteks dibatalkan.
Tunjukkan petunjuk
`ctx.Done()` adalah saluran yang ditutup ketika konteksnya dibatalkan.
Solusi tersedia setelah 3 upaya
Berdasarkan konvensi, kemana perginya parameter ctx dalam tanda tangan fungsi?
func Fetch(???, url string) ([]byte, error)Rekap
context.Contextmenyebarkan nilai pembatalan, tenggat waktu, dan terikat cakupan.Background()/TODO()sebagai akar;WithCancel/WithTimeout/WithDeadlineuntuk memperoleh.- Selalu
defer cancel()untuk melepaskan sumber daya. - Fungsi "Panjang" harus
selectdictx.Done()atau meneruskan ctx ke paket standar. - Konvensi:
ctxsebagai parameter PERTAMA, tidak pernah berada di dalam struct. WithValuehanya untuk data cakupan permintaan (ID permintaan, ID pelacakan).- Di
net/http,r.Context()dibatalkan saat klien terputus.