Context
Context adalah package yang menyediakan cara untuk membawa deadline, cancellation signals, dan value yang scoped ke request.
Contoh Masalah
Bagaimana cara:
- Mengelola request lifecycle
- Membatalkan operasi
- Menyimpan request-scoped values
Penyelesaian
package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
)
// 1. Basic context with timeout
func slowOperation(ctx context.Context) error {
select {
case <-time.After(2 * time.Second):
fmt.Println("Slow operation completed")
return nil
case <-ctx.Done():
return ctx.Err()
}
}
// 2. Context with value
type contextKey string
func withUser(ctx context.Context, username string) context.Context {
return context.WithValue(ctx, contextKey("user"), username)
}
func getUser(ctx context.Context) string {
value := ctx.Value(contextKey("user"))
if username, ok := value.(string); ok {
return username
}
return ""
}
// 3. HTTP server with context
func handleRequest(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// Add timeout
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
defer cancel()
// Add user info
ctx = withUser(ctx, "john_doe")
// Do some work
select {
case <-time.After(2 * time.Second):
fmt.Fprintln(w, "Request processed")
case <-ctx.Done():
fmt.Fprintln(w, "Request cancelled")
return
}
}
// 4. Worker pool with context
func worker(ctx context.Context, id int, jobs <-chan int, results chan<- int) {
for {
select {
case <-ctx.Done():
return
case j, ok := <-jobs:
if !ok {
return
}
fmt.Printf("worker %d started job %d\n", id, j)
time.Sleep(time.Second)
results <- j * 2
}
}
}
// 5. Database operation simulation
type DB struct{}
func (db *DB) QueryWithContext(ctx context.Context, query string) (string, error) {
select {
case <-time.After(500 * time.Millisecond):
return "query result", nil
case <-ctx.Done():
return "", ctx.Err()
}
}
// 6. Chain of operations with context
func operation1(ctx context.Context) error {
select {
case <-time.After(100 * time.Millisecond):
fmt.Println("Operation 1 completed")
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func operation2(ctx context.Context) error {
select {
case <-time.After(200 * time.Millisecond):
fmt.Println("Operation 2 completed")
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func operation3(ctx context.Context) error {
select {
case <-time.After(300 * time.Millisecond):
fmt.Println("Operation 3 completed")
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func main() {
// Contoh 1: Context with timeout
fmt.Println("Context with Timeout Example:")
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
if err := slowOperation(ctx); err != nil {
fmt.Printf("Error: %v\n", err)
}
// Contoh 2: Context with value
fmt.Printf("\nContext with Value Example:\n")
ctx = withUser(context.Background(), "alice")
fmt.Printf("User from context: %s\n", getUser(ctx))
// Contoh 3: HTTP server
fmt.Printf("\nHTTP Server Example:\n")
http.HandleFunc("/", handleRequest)
go func() {
log.Fatal(http.ListenAndServe(":8080", nil))
}()
// Contoh 4: Worker pool
fmt.Printf("\nWorker Pool Example:\n")
ctx, cancel = context.WithCancel(context.Background())
const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
// Start workers
for w := 1; w <= 3; w++ {
go worker(ctx, w, jobs, results)
}
// Send jobs
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// Collect results
for a := 1; a <= numJobs; a++ {
<-results
}
cancel()
// Contoh 5: Database operation
fmt.Printf("\nDatabase Operation Example:\n")
db := &DB{}
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
result, err := db.QueryWithContext(ctx, "SELECT * FROM users")
if err != nil {
fmt.Printf("Query error: %v\n", err)
} else {
fmt.Printf("Query result: %s\n", result)
}
// Contoh 6: Chain of operations
fmt.Printf("\nChain of Operations Example:\n")
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
if err := operation1(ctx); err != nil {
fmt.Printf("Operation 1 failed: %v\n", err)
return
}
if err := operation2(ctx); err != nil {
fmt.Printf("Operation 2 failed: %v\n", err)
return
}
if err := operation3(ctx); err != nil {
fmt.Printf("Operation 3 failed: %v\n", err)
return
}
fmt.Println("All operations completed successfully")
}
Penjelasan Kode
Basic Context
- Background context
- WithTimeout
- WithCancel
- WithDeadline
Context Values
- WithValue
- Type-safe keys
- Request-scoped data
Common Uses
- HTTP requests
- Database operations
- Worker pools
Output
Context with Timeout Example:
Slow operation completed
Context with Value Example:
User from context: alice
Worker Pool Example:
worker 1 started job 1
worker 2 started job 2
worker 3 started job 3
worker 1 started job 4
worker 2 started job 5
Database Operation Example:
Query result: query result
Chain of Operations Example:
Operation 1 completed
Operation 2 completed
Operation 3 completed
All operations completed successfully
Tips
- Selalu cancel context
- Gunakan context.Background()
- Hindari menyimpan context
- Pass context sebagai parameter pertama
- Gunakan type-safe context keys