110. Pengenalan Context & Context Tree
Arsitektur Parent-Child Context Tree dan sinyal cancellation.
Package Context
Membawa sinyal cancellation, deadline, dan request-scoped data. Jika Parent dibatalkan, seluruh Child otomatis terbatalkan secara berantai!
Contoh program
package main
import (
"context"
"fmt"
)
func main() {
ctx := context.Background()
fmt.Println("Root Context:", ctx)
}
111. context.Background, context.TODO, & WithValue
Membuat Root Context dan menyisipkan metadata request-scoped.
WithValue
context.WithValue(parent, key, value) menyisipkan data. Membaca: ctx.Value(key).
Contoh program
package main
import (
"context"
"fmt"
)
func main() {
parent := context.Background()
ctx := context.WithValue(parent, "userID", "USER-123")
fmt.Println("User ID:", ctx.Value("userID"))
}
112. context.WithCancel (Sinyal Pembatalan Manual)
Mengirim sinyal cancel untuk menghentikan Goroutines.
WithCancel
ctx, cancel := context.WithCancel(parent). Saat cancel() dipanggil, ctx.Done() menutup channel dan memberikan sinyal.
Contoh program
package main
import (
"context"
"fmt"
"time"
)
func Counter(ctx context.Context) <-chan int {
ch := make(chan int)
go func() {
defer close(ch)
n := 1
for {
select {
case <-ctx.Done():
fmt.Println("Counter dihentikan!")
return
case ch <- n:
n++
}
}
}()
return ch
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
for n := range Counter(ctx) {
fmt.Println("Angka:", n)
if n == 3 {
cancel()
break
}
}
time.Sleep(100 * time.Millisecond)
}
113. context.WithTimeout & WithDeadline
Membatalkan proses otomatis jika melebihi batas waktu.
WithTimeout & WithDeadline
WithTimeout(parent, 5*time.Second) — durasi relatif. WithDeadline(parent, time.Time) — waktu spesifik. Selalu panggil defer cancel()!
Contoh program
package main
import (
"context"
"fmt"
"time"
)
func SlowQuery(ctx context.Context) {
select {
case <-time.After(500 * time.Millisecond):
fmt.Println("Query Selesai!")
case <-ctx.Done():
fmt.Println("TIMEOUT!", ctx.Err())
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
SlowQuery(ctx)
}
114. Goroutine Leak Prevention & Best Practices
Mencegah Goroutine Leak dan konvensi penulisan parameter Context.
Goroutine Leak & Best Practices
Goroutine Leak = goroutine yang tak pernah mati karena ter-block channel. Solusi: selalu teruskan Context dan dengarkan <-ctx.Done().
Konvensi:
- Parameter
ctx context.Contextselalu di posisi PERTAMA - Jangan simpan Context di struct
- Selalu
defer cancel()
Contoh program
package main
import (
"context"
"fmt"
"runtime"
"time"
)
func SafeRoutine(ctx context.Context) {
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("Goroutine Berhasil Dihentikan!")
return
default:
time.Sleep(10 * time.Millisecond)
}
}
}()
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
SafeRoutine(ctx)
fmt.Println("Goroutines aktif:", runtime.NumGoroutine())
cancel()
time.Sleep(50 * time.Millisecond)
fmt.Println("Setelah cancel:", runtime.NumGoroutine())
}