Context Cancellation, Timeout & Deadline
đ§ context (āĻāύāĻā§āĻā§āϏāĻ) -> āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒāĻžāĻ āĻžāύā§
context āĻšāϞ⧠āĻāĻāĻāĻŋ āĻ
āĻŦāĻā§āĻā§āĻ āϝāĻž āĻāĻāĻāĻŋ goroutine-āĻā§ āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒāĻžāĻ āĻžāϤ⧠āĻĒāĻžāϰā§āĨ¤ āĻāĻ āϏāĻŋāĻāύā§āϝāĻžāϞāĻā§āϞ⧠āĻšāϤ⧠āĻĒāĻžāϰā§:
- āĻā§āϝāĻžāύāϏā§āϞā§āĻļāύ (Cancellation): âāϤā§āĻŽāĻžāϰ āĻāĻžāĻ āĻāĻāύ āĻŦāύā§āϧ āĻāϰā§āĨ¤â
- āĻāĻžāĻāĻŽāĻāĻāĻ (Timeout): âāϤā§āĻŽāĻžāϰ āĻāĻžāĻ āϝāĻĻāĻŋ ā§Ģ āϏā§āĻā§āύā§āĻĄā§āϰ āĻŽāϧā§āϝ⧠āĻļā§āώ āύāĻž āĻšā§, āϤāĻŦā§ āĻŦāύā§āϧ āĻāϰ⧠āĻĻāĻŋāĻāĨ¤â
- āĻĄā§āĻĄāϞāĻžāĻāύ (Deadline): âāϤā§āĻŽāĻžāϰ āĻāĻžāĻ āϰāĻžāϤ ā§§ā§§:ā§Ģ⧝ āĻŽāĻŋāύāĻŋāĻā§āϰ āĻŽāϧā§āϝ⧠āĻļā§āώ āĻāϰāϤ⧠āĻšāĻŦā§, āύāĻž āĻšāϞ⧠āĻŦāύā§āϧ āĻāϰ⧠āĻĻāĻŋāĻāĨ¤â
Context-āĻāϰ āĻĒā§āϰāϧāĻžāύ āĻāĻžāĻ āĻšāϞ⧠goroutine-āĻĻā§āϰ āĻāĻāĻāĻŋ āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āĻāĻžāĻā§āϰ âāϞāĻžāĻāĻĢāϏāĻžāĻāĻā§āϞâ āĻŦāĻž āĻā§āĻŦāύāĻāĻžāϞ āĻŦā§āĻāϧ⧠āĻĻā§āĻā§āĻžāĨ¤
đ§ āϏāĻŽāϏā§āϝāĻž: Goroutine Leak
Context āĻŦā§āϝāĻŦāĻšāĻžāϰā§āϰ āĻĒā§āϰāϧāĻžāύ āĻāĻžāϰāĻŖ āĻšāϞ⧠Goroutine Leak (āĻā§āϰā§āĻāĻŋāύ āϞāĻŋāĻ) āĻĒā§āϰāϤāĻŋāϰā§āϧ āĻāϰāĻžāĨ¤
āĻāĻāĻāĻŋ âāϞāĻŋāĻâ āϤāĻāύ āĻāĻā§ āϝāĻāύ āĻāĻĒāύāĻŋ āĻāĻāĻāĻŋ goroutine āĻāĻžāϞ⧠āĻāϰā§āύ āĻāĻŋāύā§āϤ⧠āϏā§āĻāĻŋ āĻļā§āώ āĻāϰāĻžāϰ āĻāĻĨāĻž āĻā§āϞ⧠āϝāĻžāύ (āĻŦāĻž āĻāϰāϤ⧠āĻĒāĻžāϰā§āύ āύāĻž)āĨ¤ goroutine-āĻāĻŋ āĻŦā§āϝāĻžāĻāĻā§āϰāĻžāĻāύā§āĻĄā§ āĻāϞāϤā§āĻ āĻĨāĻžāĻā§ āĻāĻŦāĻ āĻŽā§āĻŽā§āϰāĻŋ āĻ CPU āĻ
āĻĒāĻā§ āĻāϰā§āĨ¤
āĻāĻĻāĻžāĻšāϰāĻŖ: āϧāϰā§āύ āĻāĻāĻāĻŋ āĻā§ā§āĻŦ āϏāĻžāϰā§āĻāĻžāϰ⧠āĻāĻāĻāύ āĻāĻāĻāĻžāϰ āĻāĻāĻāĻŋ āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻĒāĻžāĻ āĻžāϞā§āĨ¤ āĻāĻĒāύāĻŋ āĻāĻāĻāĻŋ goroutine āĻāĻžāϞ⧠āĻāϰāϞā§āύ āĻĄā§āĻāĻžāĻŦā§āϏ āĻĨā§āĻā§ āϤāĻĨā§āϝ āĻāύāĻžāϰ āĻāύā§āϝāĨ¤ āĻāĻŋāύā§āϤ⧠āĻāĻāĻāĻžāϰ āϰāĻŋāĻā§ā§ā§āϏā§āĻāĻāĻŋ āĻā§āϝāĻžāύāϏā§āϞ āĻāϰ⧠āĻĻāĻŋāϞ⧠(āĻŦā§āϰāĻžāĻāĻāĻžāϰ āĻŦāύā§āϧ āĻāϰ⧠āĻĻāĻŋāϞā§)āĨ¤
ContextāĻāĻžā§āĻž: āĻāĻĒāύāĻžāϰ āĻĄā§āĻāĻžāĻŦā§āϏgoroutine-āĻāĻŋ āĻāϞāϤā§āĻ āĻĨāĻžāĻāĻŦā§āĨ¤ āϏ⧠āĻāĻžāύ⧠āύāĻž āϝ⧠āϤāĻžāϰ āĻāĻžāĻā§āϰ āĻāϰ āĻā§āύ⧠āĻĻāϰāĻāĻžāϰ āύā§āĻāĨ¤ āĻāĻāĻŋ āĻāĻāĻāĻŋ āϞāĻŋāĻāĨ¤ContextāϏāĻš: āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻā§āϝāĻžāύāϏā§āϞ āĻšāĻā§āĻžāϰ āϏāĻžāĻĨā§ āϏāĻžāĻĨā§contextāĻāĻĒāύāĻžāϰgoroutine-āĻā§ āĻāĻāĻāĻŋ âāĻŦāύā§āϧ āĻāϰā§â āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒāĻžāĻ āĻžāĻŦā§āĨ¤goroutine-āĻāĻŋ āĻāĻžāĻ āĻŦāύā§āϧ āĻāϰ⧠āĻĻā§āĻŦā§ āĻāĻŦāĻ āϰāĻŋāϏā§āϰā§āϏ āĻŽā§āĻā§āϤ āĻāϰāĻŦā§āĨ¤
đŽ Context-āĻāϰ āϧāϰāĻŖ
Go-āϤ⧠context āĻĒā§āϝāĻžāĻā§āĻāĻāĻŋ āĻāĻ āϏā§āĻŦāĻŋāϧāĻžāĻā§āϞ⧠āĻĻā§ā§āĨ¤
đš 1. context.Background()
- đ āĻāĻāĻž āĻšāϞ⧠root context
- āϏāĻžāϧāĻžāϰāĻŖāϤ
maināĻĢāĻžāĻāĻļāύ āĻŦāĻž āĻāĻāĻāĻŋ āϰāĻŋāĻā§ā§ā§āϏā§āĻā§āϰ āĻļā§āϰā§āϤ⧠āĻāĻāĻŋ āϤā§āϰāĻŋ āĻāϰāĻž āĻšā§āĨ¤ - āĻāĻāĻŋ āĻāĻāĻāĻŋ āĻāĻžāϞāĻŋ context, āĻāĻāĻž āĻāĻāύ⧠cancel āĻšā§ āύāĻž, āĻāϰ āĻā§āύ⧠āĻāĻžāĻāĻŽāĻāĻāĻ āύā§āĻāĨ¤
ctx := context.Background()đ āĻāϰ āĻāĻĒāϰ āĻāĻŋāϤā§āϤāĻŋ āĻāϰā§āĻ WithCancel, WithTimeout āĻŦāĻž WithDeadline context āϤā§āϰāĻŋ āĻāϰāĻž āĻšā§āĨ¤
đš 2. context.WithCancel(parentContext)
āĻāĻāĻŋ āĻāĻāĻāĻŋ parentContext (āϝā§āĻŽāύ Background()) āύā§ā§ āĻāĻŦāĻ āĻĻā§āĻāĻŋ āĻāĻŋāύāĻŋāϏ āϰāĻŋāĻāĻžāϰā§āύ āĻāϰā§:
- āĻāĻāĻāĻŋ āύāϤā§āύ child context (
ctx)āĨ¤ - āĻāĻāĻāĻŋ
cancelāĻĢāĻžāĻāĻļāύ (cancel)āĨ¤
āĻāĻĒāύāĻŋ āϝāĻāύāĻ cancel() āĻĢāĻžāĻāĻļāύāĻāĻŋ āĻāϞ āĻāϰāĻŦā§āύ, āϤāĻāύ āϏā§āĻ context āĻāĻŦāĻ āϤāĻžāϰ āϏāĻŦ child context cancel āĻšā§ā§ āϝāĻžā§āĨ¤
ctx, cancel := context.WithCancel(context.Background())
// `ctx` â āĻŽā§āϞ context object
// `cancel` â āĻāĻ function āĻāϞ āĻāϰāϞ⧠context âcancelâ āĻšā§ā§ āϝāĻžā§āĨ¤
// āĻāĻāĻžāύ⧠āĻāĻŽāϰāĻž āĻāĻāĻāĻŋ goroutine āĻāĻžāϞ⧠āĻāϰāĻāĻŋ āϝāĻž ā§Š āϏā§āĻā§āύā§āĻĄ āĻĒāϰ āĻĒāϰā§āϝāύā§āϤ āĻŦā§āϞāĻ āĻšā§ā§ āĻĨāĻžāĻāĻŦā§
go func() {
<-time.After(3 * time.Second)
// ā§Š āϏā§āĻā§āύā§āĻĄ āĻĒāϰ āĻĒāϰā§āϝāύā§āϤ āĻŦā§āϞāĻ āĻšā§ā§ āĻĨāĻžāĻā§, āϤāĻžāϰāĻĒāϰ āĻāĻāĻŋā§ā§ āϝāĻžāĻ
cancel() // cancel after 3 seconds
}()
<-ctx.Done()
fmt.Println("Context canceled:", ctx.Err())đ§Š Output:
Context canceled: context canceled| āĻ āĻāĻļ | āĻāĻžāĻ |
|---|---|
time.After() | āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āϏāĻŽā§ āĻĒāϰ⧠signal āĻĒāĻžāĻ āĻžā§ |
cancel() | context cancel āĻāϰā§, Done() āĻŦāύā§āϧ āĻāϰ⧠|
ctx.Done() | cancellation signal āĻļā§āύ⧠|
ctx.Err() | āĻā§āύ cancel āĻšāϞ⧠(Canceled / Timeout) āĻŦāϞ⧠|
đš 3. context.WithTimeout(parentContext, duration)
đ āĻāĻāĻāĻž āĻšāϞ⧠âauto-cancelâ āĻāϰāĻž context â āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āϏāĻŽā§ āĻĒāϰ⧠āύāĻŋāĻā§ āĻĨā§āĻā§āĻ (automatically) cancel āĻšā§ā§ āϝāĻžā§āĨ¤
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() // āĻāĻāĻž main() āĻĢāĻžāĻāĻļāύ return āĻāϰāĻžāϰ āĻ āĻŋāĻ āĻāĻā§ āϰāĻžāύ āĻšāĻŦā§āĨ¤
select {
case <-time.After(5 * time.Second):
fmt.Println("Work finished")
case <-ctx.Done():
fmt.Println("Timeout:", ctx.Err())
}đ§Š Output:
Timeout: context deadline exceededđ§ āĻŽāĻžāĻ¨ā§ ā§Š āϏā§āĻā§āύā§āĻĄā§āϰ āĻŽāϧā§āϝ⧠āĻāĻžāĻ āύāĻž āĻšāϞ⧠context āύāĻŋāĻā§āĻ cancel āĻāϰ⧠āĻĻā§ā§āĨ¤
đš 4. context.WithDeadline(parentContext, time)
đ WithTimeout āĻāϰ āĻŽāϤā§āĻ, āĻāĻŋāύā§āϤ⧠āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āϏāĻŽā§ (clock time) āĻĒāϰā§āϝāύā§āϤ wait āĻāϰā§āĨ¤
deadline := time.Now().Add(2 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()đš 5. ctx.Done()
đ ctx.Done() āĻšāϞ⧠āĻāĻāĻāĻž channel āϝāĻž close āĻšā§ā§ āϝāĻžā§ āϝāĻāύ context cancel āĻšā§āĨ¤
select {
case <-ctx.Done():
fmt.Println("đ Stopped:", ctx.Err())
}đ§ āĻāϰ āĻŽāĻžāϧā§āϝāĻŽā§ goroutine āĻŦā§āĻāϤ⧠āĻĒāĻžāϰ⧠â âāĻāĻŽāĻžāϰ āĻāĻžāĻ āĻŦāύā§āϧ āĻāϰāϤ⧠āĻšāĻŦā§āĨ¤â
đĄ Context āϝā§āĻāĻžāĻŦā§ āĻāĻžāĻ āĻāϰā§
Context-āĻāϰ āĻĻā§āĻāĻŋ āĻŽā§āϞ āĻ
āĻāĻļ: āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒāĻžāĻ āĻžāύ⧠āĻāĻŦāĻ āϏāĻŋāĻāύā§āϝāĻžāϞ āĻā§āϰāĻšāĻŖ āĻāϰāĻžāĨ¤
ā§§. āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒāĻžāĻ āĻžāύ⧠(āĻā§āϝāĻžāύāϏā§āϞ āĻāϰāĻž):
WithCancel-āĻāϰ cancel() āĻĢāĻžāĻāĻļāύ āĻāϞ āĻāϰāĻž āĻšāϞā§, āĻ
āĻĨāĻŦāĻž WithTimeout-āĻāϰ āϏāĻŽā§ āĻļā§āώ āĻšāϞ⧠context āĻā§āϝāĻžāύāϏā§āϞ āĻšā§ā§ āϝāĻžā§āĨ¤
⧍. āϏāĻŋāĻāύā§āϝāĻžāϞ āĻā§āϰāĻšāĻŖ āĻāϰāĻž (ctx.Done()):
āĻĒā§āϰāϤāĻŋāĻāĻŋ context-āĻāϰ āĻāĻāĻāĻŋ .Done() āĻŽā§āĻĨāĻĄ āĻāĻā§, āϝāĻž āĻāĻāĻāĻŋ āĻā§āϝāĻžāύā§āϞ āϰāĻŋāĻāĻžāϰā§āύ āĻāϰā§āĨ¤
ContextāϝāϤāĻā§āώāĻŖ āĻ ā§āϝāĻžāĻā§āĻāĻŋāĻ āĻĨāĻžāĻā§, āĻāĻ āĻā§āϝāĻžāύā§āϞāĻāĻŋ āĻŦā§āϞāĻ āĻĨāĻžāĻā§āĨ¤ContextāĻā§āϝāĻžāύāϏā§āϞ āĻšāĻā§āĻžāϰ āϏāĻžāĻĨā§ āϏāĻžāĻĨā§ āĻāĻ āĻā§āϝāĻžāύā§āϞāĻāĻŋ āĻŦāύā§āϧ (closed) āĻšā§ā§ āϝāĻžā§āĨ¤
āĻāĻŽāϰāĻž āĻāĻžāύāĻŋ, āĻāĻāĻāĻŋ āĻŦāύā§āϧ āĻā§āϝāĻžāύā§āϞ āĻĨā§āĻā§ āϰāĻŋāĻĄ āĻāϰāĻž āĻšāϞ⧠āϤāĻž āϏāĻžāĻĨā§ āϏāĻžāĻĨā§ āϰāĻŋāĻāĻžāϰā§āύ āĻāϰā§āĨ¤ āĻāĻŽāϰāĻž āĻāĻ āϏā§āĻŦāĻŋāϧāĻžāĻāĻŋ select-āĻāϰ āĻŽāϧā§āϝ⧠āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻŋ:
select {
case <-ctx.Done():
// Context āĻā§āϝāĻžāύāϏā§āϞ āĻšā§ā§ āĻā§āĻā§ (āĻāĻžāĻāĻŽāĻāĻāĻ āĻŦāĻž āĻŽā§āϝāĻžāύā§ā§āĻžāϞ)!
// āĻāĻāĻžāύ⧠āϏāĻŦ āĻāĻžāĻ āĻŦāύā§āϧ āĻāϰāϤ⧠āĻšāĻŦā§, āϰāĻŋāϏā§āϰā§āϏ āĻĒāϰāĻŋāώā§āĻāĻžāϰ āĻāϰāϤ⧠āĻšāĻŦā§āĨ¤
fmt.Println("āĻāĻžāĻ āĻŦāύā§āϧ āĻāϰāĻāĻŋ...")
return // goroutine āĻĨā§āĻā§ āĻŦā§āϰ āĻšā§ā§ āϝāĻžāĻ
default:
// Context āĻāĻāύ⧠āĻ
ā§āϝāĻžāĻā§āĻāĻŋāĻ āĻāĻā§, āĻāĻžāĻ āĻāĻžāϞāĻŋā§ā§ āϝāĻžāĻ
fmt.Println("āĻāĻžāĻ āĻāϞāĻā§...")
}đ Context Propagation (āĻĒā§āϰā§āĻĒāĻžāĻā§āĻļāύ)
āĻāĻāĻŋ context-āĻāϰ āϏāĻŦāĻā§āϝāĻŧā§ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ āĻŦā§āĻļāĻŋāώā§āĻā§āϝāĨ¤
āϝāĻāύ āĻāĻāĻāĻŋ Parent Context āĻā§āϝāĻžāύāϏā§āϞ āĻšā§, āϤāĻāύ āϤāĻžāϰ āĻĨā§āĻā§ āϤā§āϰāĻŋ āϏāĻŦ Child Context-āĻ āϏā§āĻŦā§āĻāĻā§āϰāĻŋā§āĻāĻžāĻŦā§ āĻā§āϝāĻžāύāϏā§āϞ āĻšā§ā§ āϝāĻžā§āĨ¤
āĻ āĻāĻžāϰāĻŖā§āĻ context āϏāĻŦāϏāĻŽā§ āĻĢāĻžāĻāĻļāύā§āϰ āĻĒā§āϰāĻĨāĻŽ āĻāϰā§āĻā§āĻŽā§āύā§āĻ āĻšāĻŋāϏā§āĻŦā§ āĻĒāĻžāϏ āĻāϰāĻž āĻšā§: func myWorker(ctx context.Context, otherArg string)āĨ¤
maināĻāĻāĻāĻŋctxāϤā§āϰāĻŋ āĻāϰā§āĨ¤maināĻāϞ āĻāϰā§funcA(ctx)āĨ¤funcAāĻāϞ āĻāϰā§funcB(ctx)āĨ¤funcBāĻāϞ āĻāϰā§funcC(ctx)āĨ¤
āϝāĻĻāĻŋ main āĻĢāĻžāĻāĻļāύ ctx-āĻā§ āĻā§āϝāĻžāύāϏā§āϞ āĻāϰ⧠(āϝā§āĻŽāύ, āĻāĻāĻāĻžāϰā§āϰ āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻāĻžāĻāĻŽāĻāĻāĻ āĻšāϞā§), āϏā§āĻ āϏāĻŋāĻāύā§āϝāĻžāϞāĻāĻŋ funcA, funcB, āĻāĻŦāĻ funcC-āϤ⧠āĻĨāĻžāĻāĻž āϏāĻŦ goroutine-āĻāϰ āĻāĻžāĻā§ āĻĒā§āĻāĻā§ āϝāĻžāĻŦā§ (<-ctx.Done())āĨ¤ āϏāĻŦāĻžāĻ āĻāĻāϝā§āĻā§ āĻāĻžāĻ āĻŦāύā§āϧ āĻāϰ⧠āĻĻā§āĻŦā§āĨ¤
đģ āĻāĻāĻā§āϰ āĻ āύā§āĻļā§āϞāύ (Exercises)
āĻāϏā§āύ, āĻāĻĒāϰā§āϰ āϏāĻŦ āϧāĻžāϰāĻŖāĻž āĻā§āĻĄ āĻāϰ⧠āĻĻā§āĻāĻŋāĨ¤
āĻ
āύā§āĻļā§āϞāύ ā§§ āĻāĻŦāĻ ā§¨: WithTimeout (āĻŽā§āϝāĻžāύā§ā§āĻžāϞ āĻā§āϝāĻžāύāϏā§āϞ āĻāĻŦāĻ āĻāĻžāĻāĻŽāĻāĻāĻ)
āĻāĻ āĻ
āύā§āĻļā§āϞāύ⧠āĻāĻŽāϰāĻž āĻāĻāĻāĻŋ worker āϤā§āϰāĻŋ āĻāϰāĻŦ āϝāĻž āĻāĻāĻāĻŋ context āĻā§āϰāĻšāĻŖ āĻāϰā§āĨ¤ āĻāĻŽāϰāĻž āĻĻā§āĻāĻŦ ā§Š āϏā§āĻā§āύā§āĻĄ āĻĒāϰ āĻāĻāĻŋ āϏā§āĻŦā§āĻāĻā§āϰāĻŋā§āĻāĻžāĻŦā§ āĻŦāύā§āϧ āĻšā§ā§ āϝāĻžā§āĨ¤
package main
import (
"context"
"fmt"
"time"
)
// worker āĻšāϞ⧠āĻāĻāĻāĻŋ goroutine āϝāĻž context āĻļā§āώ āύāĻž āĻšāĻā§āĻž āĻĒāϰā§āϝāύā§āϤ āĻāĻžāĻ āĻāϰā§
func worker(ctx context.Context, name string) {
fmt.Printf("đˇ %s: āĻāĻžāĻ āĻļā§āϰā§...\n", name)
for {
select {
case <-ctx.Done():
// āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒā§ā§ā§āĻāĻŋ!
fmt.Printf("đ %s: āĻā§āϝāĻžāύāϏā§āϞ āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒā§āϞāĻžāĻŽ, āĻāĻžāĻ āĻŦāύā§āϧ āĻāϰāĻāĻŋāĨ¤\n", name)
return // goroutine āĻĨā§āĻā§ āĻĒā§āϰāϏā§āĻĨāĻžāύ
default:
// Context āĻ āĻŋāĻ āĻĨāĻžāĻāϞ⧠āĻāĻžāĻ āĻāĻžāϞāĻŋā§ā§ āϝāĻžāĻ
fmt.Printf("âī¸ %s: āĻāĻžāĻ āĻāϰāĻāĻŋ...\n", name)
time.Sleep(1 * time.Second) // āĻāĻžāĻā§āϰ āϏāĻŋāĻŽā§āϞā§āĻļāύ
}
}
}
func main() {
// ā§§. āĻāĻāĻāĻŋ parent context āϤā§āϰāĻŋ āĻāϰāĻŋ
parentCtx := context.Background()
// ⧍. ā§Š āϏā§āĻā§āύā§āĻĄā§āϰ āĻāĻāĻāĻŋ āĻāĻžāĻāĻŽāĻāĻāĻ āϏāĻš child context āϤā§āϰāĻŋ āĻāϰāĻŋ
ctx, cancel := context.WithTimeout(parentCtx, 3*time.Second)
// ā§Š. (āĻā§āĻŦāĻ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ) āĻāĻžāĻ āĻļā§āώ⧠cancel() āĻāϞ āĻāϰāĻž
// āĻāĻāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āĻāϰ⧠āϝ⧠context-āĻāϰ āϏāĻžāĻĨā§ āϝā§āĻā§āϤ āϏāĻŦ āϰāĻŋāϏā§āϰā§āϏ āĻŽā§āĻā§āϤ āĻšāĻŦā§āĨ¤
// āϝāĻĻāĻŋāĻ āĻāĻžāĻāĻŽāĻāĻāĻ āĻšāϞ⧠āĻāĻāĻŋ āύāĻŋāĻā§ āĻĨā§āĻā§āĻ āĻā§āϝāĻžāύāϏā§āϞ āĻšāĻŦā§,
// āĻāĻŋāύā§āϤ⧠āϝāĻĻāĻŋ worker āĻāĻā§ āĻāĻžāĻ āĻļā§āώ āĻāϰ⧠āĻĢā§āϞā§, āϤāĻŦā§ defer cancel() āϰāĻŋāϏā§āϰā§āϏ āϞāĻŋāĻ āĻ ā§āĻāĻžā§āĨ¤
defer cancel()
fmt.Println("đ main: āĻā§āĻžāϰā§āĻāĻžāϰ āĻāĻžāϞ⧠āĻāϰāĻāĻŋ (ā§Š āϏā§āĻā§āύā§āĻĄ āĻāĻžāĻāĻŽāĻāĻāĻ)...")
go worker(ctx, "Worker-1")
// main goroutine-āĻā§ ā§Ģ āϏā§āĻā§āύā§āĻĄ āĻāĻžāϞ⧠āϰāĻžāĻāĻŋ āϝāĻžāϤ⧠worker-āĻāϰ āĻĒā§āϰāϏā§āĻĨāĻžāύ āĻĻā§āĻāϤ⧠āĻĒāĻžāϰāĻŋ
time.Sleep(5 * time.Second)
fmt.Println("đ main: āĻĒā§āϰā§āĻā§āϰāĻžāĻŽ āĻļā§āώāĨ¤")
}āĻāĻāĻāĻĒā§āĻ:
đ main: āĻā§āĻžāϰā§āĻāĻžāϰ āĻāĻžāϞ⧠āĻāϰāĻāĻŋ (ā§Š āϏā§āĻā§āύā§āĻĄ āĻāĻžāĻāĻŽāĻāĻāĻ)...
đˇ Worker-1: āĻāĻžāĻ āĻļā§āϰā§...
âī¸ Worker-1: āĻāĻžāĻ āĻāϰāĻāĻŋ...
âī¸ Worker-1: āĻāĻžāĻ āĻāϰāĻāĻŋ...
âī¸ Worker-1: āĻāĻžāĻ āĻāϰāĻāĻŋ...
đ Worker-1: āĻā§āϝāĻžāύāϏā§āϞ āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒā§āϞāĻžāĻŽ, āĻāĻžāĻ āĻŦāύā§āϧ āĻāϰāĻāĻŋāĨ¤
đ main: āĻĒā§āϰā§āĻā§āϰāĻžāĻŽ āĻļā§āώāĨ¤āĻŦāĻŋāĻļā§āϞā§āώāĻŖ: Worker-1 āĻ āĻŋāĻ ā§Š āϏā§āĻā§āύā§āĻĄ āĻāĻžāĻ āĻāϰāĻžāϰ āĻĒāϰ <-ctx.Done() āĻĨā§āĻā§ āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒāĻžā§ āĻāĻŦāĻ āĻŦāύā§āϧ āĻšā§ā§ āϝāĻžā§āĨ¤
āĻ āύā§āĻļā§āϞāύ ā§Š, ā§Ē āĻāĻŦāĻ ā§Ģ: Context āĻā§āĻāύ āĻāĻŦāĻ āĻā§āĻžāϰā§āĻāĻžāϰ āĻā§āϝāĻžāύāϏā§āϞā§āĻļāύ
āĻāĻāĻžāύ⧠āĻāĻŽāϰāĻž āĻĻā§āĻāĻŦ context āĻā§āĻāĻžāĻŦā§ āĻāĻāĻžāϧāĻŋāĻ āĻĢāĻžāĻāĻļāύā§āϰ āĻŽāϧā§āϝ⧠(āĻā§āĻāύ) āĻĒāĻžāϏ āĻāϰāĻž āĻšā§ āĻāĻŦāĻ āĻā§āϝāĻžāύāϏā§āϞā§āĻļāύ āĻā§āĻāĻžāĻŦā§ āĻāĻžāĻ āĻāϰā§āĨ¤
package main
import (
"context"
"fmt"
"time"
)
// step3: āĻāϏāϞ āĻāĻžāĻ āĻāĻāĻžāύ⧠āĻšā§ (āĻĄā§āĻāĻžāĻŦā§āϏ āĻā§ā§ā§āϰāĻŋ āϏāĻŋāĻŽā§āϞā§āĻļāύ)
func step3(ctx context.Context) {
fmt.Println(" [Step 3]: āĻĄā§āĻāĻžāĻŦā§āϏ āĻā§ā§ā§āϰāĻŋ āĻļā§āϰā§... (⧍ āϏā§āĻā§āύā§āĻĄ āϞāĻžāĻāĻŦā§)")
select {
case <-time.After(2 * time.Second):
// āĻāĻžāĻ āϏāĻŽā§āĻĒāύā§āύ
fmt.Println(" [Step 3]: āĻĄā§āĻāĻžāĻŦā§āϏ āĻā§ā§ā§āϰāĻŋ āϏāĻĢāϞāĨ¤")
case <-ctx.Done():
// āĻāĻžāĻ āĻļā§āώ āĻšāĻā§āĻžāϰ āĻāĻā§āĻ āĻā§āϝāĻžāύāϏā§āϞ āϏāĻŋāĻāύā§āϝāĻžāϞ āĻāϞā§
fmt.Println(" [Step 3]: đ āĻĄā§āĻāĻžāĻŦā§āϏ āĻā§ā§ā§āϰāĻŋ āĻā§āϝāĻžāύāϏā§āϞāĻĄ!")
}
}
// step2: āĻĄā§āĻāĻž āĻĒā§āϰāϏā§āϏ āĻāϰā§
func step2(ctx context.Context) {
fmt.Println(" [Step 2]: āĻĄā§āĻāĻž āĻĒā§āϰāϏā§āϏāĻŋāĻ āĻļā§āϰā§...")
// āĻāĻžāĻ āĻāϰāĻžāϰ āĻāĻā§ āĻā§āĻ āĻāϰāĻž (Early exit)
if ctx.Err() != nil {
fmt.Println(" [Step 2]: đ āĻļā§āϰā§āϤā§āĻ āĻā§āϝāĻžāύāϏā§āϞ āĻāĻŋāϞā§, āĻāĻžāĻ āĻļā§āϰā§āĻ āĻāϰāϞāĻžāĻŽ āύāĻžāĨ¤")
return
}
step3(ctx) // context āύāĻŋāĻā§ āĻĒāĻžāϏ āĻāϰāĻž
fmt.Println(" [Step 2]: āĻĄā§āĻāĻž āĻĒā§āϰāϏā§āϏāĻŋāĻ āĻļā§āώāĨ¤")
}
// step1: āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻšā§āϝāĻžāύā§āĻĄā§āϞ āĻāϰā§
func step1(ctx context.Context) {
fmt.Println("[Step 1]: āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻšā§āϝāĻžāύā§āĻĄā§āϞāĻŋāĻ āĻļā§āϰā§...")
step2(ctx) // context āύāĻŋāĻā§ āĻĒāĻžāϏ āĻāϰāĻž
fmt.Println("[Step 1]: āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻšā§āϝāĻžāύā§āĻĄā§āϞāĻŋāĻ āĻļā§āώāĨ¤")
}
func main() {
// === āϏāĻŋāύāĻžāϰāĻŋāĻ ā§§: āϏāĻĢāϞ (āĻāĻžāĻāĻŽāĻāĻāĻā§āϰ āĻāĻā§āĻ āĻāĻžāĻ āĻļā§āώ) ===
fmt.Println("--- āϏāĻŋāύāĻžāϰāĻŋāĻ ā§§: āϏāĻĢāϞ āϰāĻŋāĻā§ā§ā§āϏā§āĻ (āĻāĻžāĻāĻŽāĻāĻāĻ ā§Š āϏā§āĻā§āύā§āĻĄ) ---")
ctxSuccess, cancelSuccess := context.WithTimeout(context.Background(), 3*time.Second)
defer cancelSuccess()
step1(ctxSuccess)
fmt.Println("\n--- āϏāĻŋāύāĻžāϰāĻŋāĻ ā§¨: āĻā§āϝāĻžāύāϏā§āϞāĻĄ (āĻāĻžāĻāĻŽāĻāĻāĻ ā§§ āϏā§āĻā§āύā§āĻĄ) ---")
// === āϏāĻŋāύāĻžāϰāĻŋāĻ ā§¨: āĻā§āϝāĻžāύāϏā§āϞāĻĄ (āĻāĻžāĻāĻŽāĻāĻāĻā§āϰ āĻāĻā§āĻ āϏāĻŋāĻāύā§āϝāĻžāϞ) ===
ctxTimeout, cancelTimeout := context.WithTimeout(context.Background(), 1*time.Second)
defer cancelTimeout()
step1(ctxTimeout)
// āĻā§āϝāĻžāύāϏā§āϞā§āĻļāύā§āϰ āĻĒā§āϰāĻāĻžāĻŦ āĻĻā§āĻāĻžāϰ āĻāύā§āϝ āĻāĻāĻā§ āĻ
āĻĒā§āĻā§āώāĻž
time.Sleep(2 * time.Second)
fmt.Println("--- āĻĒā§āϰā§āĻā§āϰāĻžāĻŽ āĻļā§āώ ---")
}āĻāĻāĻāĻĒā§āĻ:
--- āϏāĻŋāύāĻžāϰāĻŋāĻ ā§§: āϏāĻĢāϞ āϰāĻŋāĻā§ā§ā§āϏā§āĻ (āĻāĻžāĻāĻŽāĻāĻāĻ ā§Š āϏā§āĻā§āύā§āĻĄ) ---
[Step 1]: āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻšā§āϝāĻžāύā§āĻĄā§āϞāĻŋāĻ āĻļā§āϰā§...
[Step 2]: āĻĄā§āĻāĻž āĻĒā§āϰāϏā§āϏāĻŋāĻ āĻļā§āϰā§...
[Step 3]: āĻĄā§āĻāĻžāĻŦā§āϏ āĻā§ā§ā§āϰāĻŋ āĻļā§āϰā§... (⧍ āϏā§āĻā§āύā§āĻĄ āϞāĻžāĻāĻŦā§)
[Step 3]: āĻĄā§āĻāĻžāĻŦā§āϏ āĻā§ā§ā§āϰāĻŋ āϏāĻĢāϞāĨ¤
[Step 2]: āĻĄā§āĻāĻž āĻĒā§āϰāϏā§āϏāĻŋāĻ āĻļā§āώāĨ¤
[Step 1]: āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻšā§āϝāĻžāύā§āĻĄā§āϞāĻŋāĻ āĻļā§āώāĨ¤
--- āϏāĻŋāύāĻžāϰāĻŋāĻ ā§¨: āĻā§āϝāĻžāύāϏā§āϞāĻĄ (āĻāĻžāĻāĻŽāĻāĻāĻ ā§§ āϏā§āĻā§āύā§āĻĄ) ---
[Step 1]: āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻšā§āϝāĻžāύā§āĻĄā§āϞāĻŋāĻ āĻļā§āϰā§...
[Step 2]: āĻĄā§āĻāĻž āĻĒā§āϰāϏā§āϏāĻŋāĻ āĻļā§āϰā§...
[Step 3]: āĻĄā§āĻāĻžāĻŦā§āϏ āĻā§ā§ā§āϰāĻŋ āĻļā§āϰā§... (⧍ āϏā§āĻā§āύā§āĻĄ āϞāĻžāĻāĻŦā§)
[Step 3]: đ āĻĄā§āĻāĻžāĻŦā§āϏ āĻā§ā§ā§āϰāĻŋ āĻā§āϝāĻžāύāϏā§āϞāĻĄ!
[Step 2]: āĻĄā§āĻāĻž āĻĒā§āϰāϏā§āϏāĻŋāĻ āĻļā§āώāĨ¤
[Step 1]: āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻšā§āϝāĻžāύā§āĻĄā§āϞāĻŋāĻ āĻļā§āώāĨ¤
--- āĻĒā§āϰā§āĻā§āϰāĻžāĻŽ āĻļā§āώ ---āĻŦāĻŋāĻļā§āϞā§āώāĻŖ:
- āϏāĻŋāύāĻžāϰāĻŋāĻ ā§§: ā§Š āϏā§āĻā§āύā§āĻĄā§āϰ āĻāĻžāĻāĻŽāĻāĻāĻ āĻāĻŋāϞā§, āĻāĻŋāύā§āϤā§
step3-āĻāϰ āĻāĻžāĻ ā§¨ āϏā§āĻā§āύā§āĻĄā§ āĻļā§āώ āĻšā§ā§ āĻā§āĻā§āĨ¤ āϤāĻžāĻ<-ctx.Done()āϏāĻŋāĻāύā§āϝāĻžāϞ āĻāϏāĻžāϰ āĻāĻā§āĻ<-time.After()āϏāĻŋāĻāύā§āϝāĻžāϞāĻāĻŋ āĻāĻŋāϤā§āĻā§āĨ¤ - āϏāĻŋāύāĻžāϰāĻŋāĻ ā§¨: ā§§ āϏā§āĻā§āύā§āĻĄā§āϰ āĻāĻžāĻāĻŽāĻāĻāĻ āĻāĻŋāϞā§, āĻāĻŋāύā§āϤā§
step3-āĻāϰ āĻāĻžāĻ ā§¨ āϏā§āĻā§āύā§āĻĄ āϞāĻžāĻāĻžāϰ āĻāĻĨāĻžāĨ¤selectāϏā§āĻā§āĻāĻŽā§āύā§āĻāĻāĻŋ āĻĻā§āĻāϞ⧠āϝā§<-ctx.Done()(ā§§ āϏā§āĻā§āύā§āĻĄ) āϏāĻŋāĻāύā§āϝāĻžāϞāĻāĻŋ<-time.After()(⧍ āϏā§āĻā§āύā§āĻĄ) āϏāĻŋāĻāύā§āϝāĻžāϞā§āϰ āĻāĻā§ āĻĒā§āϰāϏā§āϤā§āϤ āĻšā§ā§āĻā§āĨ¤ āϤāĻžāĻ āĻāĻāĻŋ āĻā§āϝāĻžāύāϏā§āϞā§āĻļāύ āĻĒāĻžāĻĨāĻāĻŋ āĻŦā§āĻā§ āύāĻŋāϞā§āĨ¤
đĢ āϏāĻžāϧāĻžāϰāĻŖ āĻā§āϞ āĻāĻŦāĻ â āϏāĻ āĻŋāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ
Context āĻā§āĻŦ āĻļāĻā§āϤāĻŋāĻļāĻžāϞā§, āĻāĻŋāύā§āϤ⧠āĻāĻāĻŋ āĻā§āϞāĻāĻžāĻŦā§ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻžāĻ āĻā§āĻŦ āϏāĻšāĻāĨ¤
| āϏāĻžāϧāĻžāϰāĻŖ āĻā§āϞ (Avoid) | â āϏāĻ āĻŋāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ (Do) |
|---|---|
context āĻāĻāĻāĻŋ struct-āĻāϰ āĻŽāϧā§āϝ⧠āϏā§āĻā§āϰ āĻāϰāĻžāĨ¤ | context-āĻā§ āϏāĻŦāϏāĻŽā§ āĻĢāĻžāĻāĻļāύā§āϰ āĻĒā§āϰāĻĨāĻŽ āĻāϰā§āĻā§āĻŽā§āύā§āĻ āĻšāĻŋāϏā§āĻŦā§ āĻĒāĻžāϏ āĻāϰā§āύ: func(ctx context.Context, ...)āĨ¤ |
context.Background() āϏāĻŦ āĻāĻžā§āĻāĻžā§ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻžāĨ¤ | context.Background() āĻļā§āϧ⧠main āĻŦāĻž āϰāĻŋāĻā§ā§ā§āϏā§āĻā§āϰ āĻļā§āϰā§āϤ⧠āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤ āĻŦāĻžāĻāĻŋ āϏāĻŦ āĻāĻžā§āĻāĻžā§ āĻĒāĻžāϏ āĻāϰāĻž ctx āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤ |
cancel() āĻĢāĻžāĻāĻļāύ āĻāϞ āύāĻž āĻāϰāĻžāĨ¤ | defer cancel() āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤ context.With... āĻāϞ āĻāϰāĻžāϰ āϏāĻžāĻĨā§ āϏāĻžāĻĨā§āĻ defer cancel() āϞāĻŋāĻā§ āĻĢā§āϞā§āύāĨ¤ āĻāĻāĻŋ āϰāĻŋāϏā§āϰā§āϏ āϞāĻŋāĻ āĻ ā§āĻāĻžā§āĨ¤ |
context.TODO() āĻĒā§āϰā§āĻĄāĻžāĻāĻļāύ āĻā§āĻĄā§ āϰā§āĻā§ āĻĻā§āĻā§āĻžāĨ¤ | TODO() āĻļā§āϧ⧠āϤāĻāύāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύ āϝāĻāύ āĻāĻĒāύāĻŋ āύāĻŋāĻļā§āĻāĻŋāϤ āύāύ āĻā§āύ context āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻŦā§āύ (āĻāĻŦāĻ āĻĒāϰ⧠āϤāĻž āĻ āĻŋāĻ āĻāϰāĻŦā§āύ)āĨ¤ |
nil context āĻĒāĻžāϏ āĻāϰāĻžāĨ¤ | nil āĻĒāĻžāϏ āύāĻž āĻāϰā§, āϝāĻĻāĻŋ āĻā§āύ⧠context āύāĻž āĻĨāĻžāĻā§ āϤāĻŦā§ context.Background() āĻĒāĻžāϏ āĻāϰā§āύāĨ¤ |
context-āĻāϰ āĻŽāϧā§āϝ⧠āĻĄā§āĻāĻž āĻĒāĻžāϏ āĻāϰāĻž (WithValue)āĨ¤ | WithValue āĻā§āĻŋā§ā§ āĻāϞā§āύ, āϝāĻĻāĻŋ āύāĻž āϰāĻŋāĻā§ā§ā§āϏā§āĻ-āϏā§āĻā§āĻĒāĻĄ āĻĄā§āĻāĻž (āϝā§āĻŽāύ trace ID, user ID) āĻĒāĻžāϏ āĻāϰāĻžāϰ āĻĻāϰāĻāĻžāϰ āĻšā§āĨ¤ āĻāĻāĻŋ āϏāĻŋāĻāύā§āϝāĻžāϞāĻŋāĻā§ā§āϰ āĻāύā§āϝ āύā§āĨ¤ |
đš 4. context.WithDeadline(parent, timePoint)
đ WithTimeout āĻāϰ āĻŽāϤā§āĻ, āĻāĻŋāύā§āϤ⧠āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āϏāĻŽā§ (clock time) āĻĒāϰā§āϝāύā§āϤ wait āĻāϰā§āĨ¤
deadline := time.Now().Add(2 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()đ§Š Context Propagation āĻā§āĻāĻžāĻŦā§ āĻāĻžāĻ āĻāϰā§?
Context āĻšāϞ⧠parent â child chain.
Background()
âââ WithCancel()
âââ WithTimeout()
âââ WithDeadline()āϝāĻĻāĻŋ parent cancel āĻšā§ â āϏāĻŦ child context āĻ cancel āĻšā§āĨ¤ āĻāĻāĻžāĻ āĻŦāϞ⧠propagationāĨ¤
âī¸ āĻā§āύ Context āĻĢāĻžāĻāĻļāύā§āϰ āĻĒā§āϰāĻĨāĻŽ argument āĻšā§?
đ āĻāĻžāϰāĻŖ Go design principle āĻ āύā§āϝāĻžā§ā§ context āĻšāϞ⧠request-scoped metadataāĨ¤ āĻāĻāĻž function āĻāϰ lifecycle āύāĻŋā§āύā§āϤā§āϰāĻŖ āĻāϰā§āĨ¤
â Best Practice:
func fetchData(ctx context.Context, url string) errorâ Wrong:
func fetchData(url string, ctx context.Context)đ§ āĻāĻžāϰāĻŖ: Context āϏāϰā§āĻŦāĻĻāĻž āĻāĻĒāϰā§āϰ āĻĻāĻŋāĻ āĻĨā§āĻā§ āύāĻŋāĻā§āϰ āĻĻāĻŋāĻā§ propagate āĻšā§āĨ¤
đĄ Context āĻāĻŋāĻāĻžāĻŦā§ Goroutine Leak āĻāĻāĻāĻžā§
Goroutine leak āĻšā§ āϝāĻāύ goroutine cancel signal āύāĻž āĻĒā§ā§ā§ āĻāĻŋāϰāĻĻāĻŋāύ āĻ āĻĒā§āĻā§āώāĻž āĻāϰā§āĨ¤
â āĻāĻĻāĻžāĻšāϰāĻŖ:
func worker(ch <-chan int) {
for v := range ch {
fmt.Println(v)
}
}āϝāĻĻāĻŋ ch āĻāĻāύ⧠close āύāĻž āĻšā§ â goroutine āĻāĻŋāϰāĻĻāĻŋāύ block āĻĨāĻžāĻāĻŦā§āĨ¤
â āϏāĻŽāĻžāϧāĻžāύ: Context āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠āĻŦāύā§āϧ āĻāϰāĻžāĨ¤
func worker(ctx context.Context, ch <-chan int) {
for {
select {
case v := <-ch:
fmt.Println(v)
case <-ctx.Done():
fmt.Println("Worker stopped")
return
}
}
}đģ Exercises
đ§Š 1ī¸âŖ Goroutine that stops when context is canceled
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("đ Goroutine stopped")
return
default:
fmt.Println("đ Running...")
time.Sleep(500 * time.Millisecond)
}
}
}()
time.Sleep(2 * time.Second)
cancel() // stop after 2 seconds
time.Sleep(1 * time.Second)
}đ§Š 2ī¸âŖ WithTimeout â stop after 3 seconds
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("â° Timeout reached:", ctx.Err())
return
default:
fmt.Println("âī¸ Working...")
time.Sleep(500 * time.Millisecond)
}
}
}()
time.Sleep(4 * time.Second)đ§Š 3ī¸âŖ Chain 3 Goroutines passing context downstream
func worker(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name, "stopped")
return
default:
fmt.Println(name, "working...")
time.Sleep(700 * time.Millisecond)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
go worker(ctx, "đ§ą Worker 1")
go worker(ctx, "đ§ Worker 2")
go worker(ctx, "âī¸ Worker 3")
<-ctx.Done()
fmt.Println("All workers stopped:", ctx.Err())
}đ§Š 4ī¸âŖ Cleanup with <-ctx.Done()
select {
case <-ctx.Done():
fmt.Println("Cleaning up resources...")
return
}đ§Š 5ī¸âŖ Worker respecting cancellation
func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d shutting down\n", id)
return
default:
fmt.Printf("Worker %d doing work\n", id)
time.Sleep(500 * time.Millisecond)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
for i := 1; i <= 3; i++ {
go worker(ctx, i)
}
<-ctx.Done()
fmt.Println("đ All workers canceled:", ctx.Err())
}â ī¸ Common Mistakes & Correct Usage
| āĻā§āϞ āĻŦā§āϝāĻŦāĻšāĻžāϰ â | āϏāĻ āĻŋāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ â |
|---|---|
| Context āύāĻž āĻĒāĻžāĻ āĻžāύ⧠| āϏāĻŦ goroutine/fn-āĻ context āĻĒāĻžāĻ āĻžāĻ |
| Context āĻļā§āώā§āĻ cancel() āύāĻž āĻāϰāĻž | āϏāĻŦāϏāĻŽā§ defer cancel() āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠|
| cancel() āύāĻž āĻĄāĻžāĻāĻž | resource leak āĻšāϤ⧠āĻĒāĻžāϰ⧠|
| context child chain āύāĻž āĻŦāĻžāύāĻžāύ⧠| parent â child propagation āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠|
context.TODO() āĻā§āϞāĻāĻžāĻŦā§ āĻŦā§āϝāĻŦāĻšāĻžāϰ | āĻļā§āϧā§āĻŽāĻžāϤā§āϰ placeholder āĻšāĻŋāϏā§āĻŦā§ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰ⧠|
<-ctx.Done() ignore āĻāϰāĻž | āϏāĻŦ worker āĻ respect āĻāϰāĻž āĻāĻāĻŋāϤ |
đ§ž Summary (āĻŦāĻžāĻāϞāĻžā§ āϏāĻžāϰāϏāĻāĻā§āώā§āĻĒ)
| āĻŦāĻŋāώ⧠| āĻŦāϰā§āĻŖāύāĻž |
|---|---|
context.Background() | root context |
WithCancel | manual cancel |
WithTimeout | āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āϏāĻŽā§ āĻĒāϰ auto-cancel |
WithDeadline | āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āϏāĻŽā§ āĻĒāϰā§āϝāύā§āϤ valid |
ctx.Done() | context cancel signal |
ctx.Err() | āĻā§āύ cancel āĻšāϞ⧠|
| Context chain | parent cancel āĻšāϞ⧠āϏāĻŦ child cancel |
| Leak prevention | goroutine cancel signal āĻĒā§āϞ⧠safely stop āĻšā§ |
āĻāĻāĻāύ āϏāĻŋāύāĻŋā§āϰāĻŋ āĻĄā§āĻā§āϞāĻĒāĻžāϰ āĻŦāĻž āĻāϰā§āĻāĻŋāĻā§āĻā§āĻ āĻšāĻŋāϏā§āĻŦā§ Context āϏāĻŽā§āĻĒāϰā§āĻā§ āϝāĻž āϝāĻž āĻāĻžāύāĻž āĻ āĻĒāϰāĻŋāĻšāĻžāϰā§āϝ, āϤāĻžāϰ āϏāĻŦāĻāĻŋāĻā§ āĻāĻāĻžāύ⧠āĻā§āĻāĻŋā§ā§ āĻĻā§āĻā§āĻž āĻšāϞā§āĨ¤
đ Go Context: The Nervous System of Production Apps
Go-āϤ⧠Context āĻā§āύ⧠āϏāĻžāϧāĻžāϰāĻŖ āĻā§āϰāĻŋā§ā§āĻŦāϞ āύā§; āĻāĻāĻŋ āĻāĻĒāύāĻžāϰ āĻ
ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύā§āϰ Nervous System āĻŦāĻž āϏā§āύāĻžā§ā§āϤāύā§āϤā§āϰāĨ¤ āĻāĻāĻāĻŋ āϰāĻŋāĻā§ā§ā§āϏā§āĻ āϝāĻāύ āϏāĻžāϰā§āĻāĻžāϰ⧠āĻĸā§āĻā§, āϤāĻāύ Context āϤāĻžāϰ āϏāĻžāĻĨā§ āĻĒā§āϰ⧠āϏāĻŋāϏā§āĻā§āĻŽā§ āĻĒā§āϰāĻŦāĻžāĻšāĻŋāϤ āĻšā§ āĻāĻŦāĻ āύāĻŋāϰā§āϧāĻžāϰāĻŖ āĻāϰ⧠āϰāĻŋāĻā§ā§ā§āϏā§āĻāĻāĻŋ āĻŦā§āĻāĻā§ āĻĨāĻžāĻāĻŦā§ āύāĻžāĻāĻŋ āĻŽāĻžāϰāĻž āϝāĻžāĻŦā§ (Cancel āĻšāĻŦā§)āĨ¤
Production Philosophy: âNever start a goroutine without knowing how it will stop.â â Context āĻšāϞ⧠āϏā§āĻ āϏā§āĻāĻĒ āĻŦāĻžāĻāύāĨ¤
ā§§. Production Hierarchy (Context Tree)
āĻĒā§āϰā§āĻĄāĻžāĻāĻļāύ āĻ ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύ⧠Context āϏāϰā§āĻŦāĻĻāĻž āĻāĻāĻāĻŋ Tree āĻāϰ āĻŽāϤ⧠āĻāĻžāĻ āĻāϰā§āĨ¤
Background Context (Root)
âââ HTTP Request Context
âââ Database Query Context
âââ API Call Context
âââ Redis Cache Context- Root:
context.Background()(āĻ ā§āϝāĻžāĻĒ āĻāĻžāϞ⧠āĻšāĻā§āĻžāϰ āϏāĻŽā§)āĨ¤ - Parent: āϝāĻāύ HTTP āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻāϏ⧠(
http.Request). - Children: āϝāĻāύ āĻāĻĒāύāĻŋ DB āĻā§ā§ā§āϰāĻŋ āĻŦāĻž āĻ
āύā§āϝ API āĻāϞ āĻāϰā§āύ, āϤāĻāύ Parent āĻĨā§āĻā§ āύāϤā§āύ Context āϤā§āϰāĻŋ āĻšā§ (
WithTimeout)āĨ¤
Rule: āϝāĻĻāĻŋ Parent āĻŽāĻžāϰāĻž āϝāĻžā§ (User cancel request), āϤāĻŦā§ āϤāĻžāϰ āϏāĻŦ Children (DB, API calls) āϏāĻžāĻĨā§ āϏāĻžāĻĨā§ āϏāĻŋāĻāύā§āϝāĻžāϞ āĻĒāĻžāĻŦā§ āĻāĻŦāĻ āĻŦāύā§āϧ āĻšā§ā§ āϝāĻžāĻŦā§āĨ¤ āĻāĻāĻŋ āϏāĻžāϰā§āĻāĻžāϰā§āϰ āϰāĻŋāϏā§āϰā§āϏ āĻŦāĻžāĻāĻāĻžā§āĨ¤
⧍. Context-āĻāϰ āĻĒā§āϰāĻāĻžāϰāĻā§āĻĻ (Production Use-Cases)
| Context Type | āĻāĻāύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻŦā§āύ? (Real World) |
|---|---|
Background() | āĻļā§āϧ⧠main() āĻĢāĻžāĻāĻļāύ āĻŦāĻž āĻ
ā§āϝāĻžāĻĒ āϏā§āĻāĻžāϰā§āĻāĻāĻĒā§āĨ¤ |
TODO() | āϝāĻāύ āĻā§āĻĄ āϞāĻŋāĻāĻā§āύ āĻāĻŋāύā§āϤ⧠āĻāĻāύ⧠āĻāĻžāύā§āύ āύāĻž āĻā§āύ Context āĻĻā§āĻŦā§āύ (Refactoring-āĻāϰ āϏāĻŽā§)āĨ¤ |
WithCancel | āϝāĻāύ āĻŽā§āϝāĻžāύā§ā§āĻžāϞāĻŋ āĻā§āύ⧠āĻĒā§āϰāϏā§āϏ āĻŦāύā§āϧ āĻāϰāϤ⧠āĻāĻžāύ (āϝā§āĻŽāύ: Graceful Shutdown)āĨ¤ |
WithTimeout | āϏāĻŦāĻā§ā§ā§ āĻŦā§āĻļāĻŋ āĻŦā§āϝāĻŦāĻšā§āϤāĨ¤ DB Query, External API Call āĻŦāĻž āϝā§āĻā§āύ⧠I/O āĻ āĻĒāĻžāϰā§āĻļāύā§āĨ¤ |
WithDeadline | āϝāĻāύ āύāĻŋāϰā§āĻĻāĻŋāώā§āĻ āĻā§āĻŋāϰ āϏāĻŽā§ (āϝā§āĻŽāύ: âāϰāĻžāϤ ⧧⧍āĻāĻžāϰ āĻāĻā§â) āĻāĻžāĻ āĻļā§āώ āĻšāϤā§āĻ āĻšāĻŦā§āĨ¤ |
WithValue | āĻļā§āϧā§āĻŽāĻžāϤā§āϰ Request-Scoped Data (Trace ID, Auth Token) āĻĒāĻžāϏ āĻāϰāϤā§āĨ¤ āĻāĻāύ⧠āĻĢāĻžāĻāĻļāύ āĻĒā§āϝāĻžāϰāĻžāĻŽāĻŋāĻāĻžāϰ āĻĒāĻžāϏ āĻāϰāĻŦā§āύ āύāĻžāĨ¤ |
ā§Š. Production Pattern: HTTP Request Handling
āĻāĻāĻāĻŋ āĻāĻĻāϰā§āĻļ āĻĒā§āϰā§āĻĄāĻžāĻāĻļāύ āϏāĻžāϰā§āĻāĻžāϰ⧠āĻā§āϞāĻžāϝāĻŧā§āύā§āĻ āϝāĻĻāĻŋ āϏāĻāϝā§āĻ āĻŦāĻŋāĻā§āĻāĻŋāύā§āύ āĻāϰā§, āϤāĻŦā§ āϏāĻžāϰā§āĻāĻžāϰā§āϰ āĻāĻžāĻāĻ āĻŦāύā§āϧ āĻšāĻāϝāĻŧāĻž āĻāĻāĻŋāϤāĨ¤
func handler(w http.ResponseWriter, r *http.Request) {
// ā§§. http.Request āύāĻŋāĻā§āĻ āĻāĻāĻāĻŋ context āύāĻŋāϝāĻŧā§ āĻāϏā§
ctx := r.Context()
fmt.Println("Processing request...")
select {
case <-time.After(5 * time.Second): // āĻāĻžāϰ⧠āĻāĻžāĻ āϏāĻŋāĻŽā§āϞā§āĻļāύ
w.Write([]byte("Request Processed"))
case <-ctx.Done(): // ⧍. āϝāĻĻāĻŋ āĻāĻāĻāĻžāϰ āĻŦā§āϰāĻžāĻāĻāĻžāϰ āĻā§āĻā§ āĻĻā§āϝāĻŧ
err := ctx.Err()
fmt.Println("Request canceled by user:", err)
http.Error(w, err.Error(), http.StatusRequestTimeout)
}
}
ā§Ē. Production Pattern: Database Timeout (Crucial)
āĻĒā§āϰā§āĻĄāĻžāĻāĻļāύ⧠āĻāĻāύ⧠db.Query āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻŦā§āύ āύāĻž, āϏāϰā§āĻŦāĻĻāĻž db.QueryContext āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻŦā§āύāĨ¤ āĻāĻāĻŋ āĻĄā§āĻāĻžāĻŦā§āϏ āĻšā§āϝāĻžāĻ āĻšāĻā§āĻž āĻĨā§āĻā§ āĻŦāĻžāĻāĻāĻžā§āĨ¤
func getUser(ctx context.Context, db *sql.DB, id int) {
// ā§§. āĻĒā§āϝāĻžāϰā§āύā§āĻ context āĻĨā§āĻā§ āύāϤā§āύ context, āϝāĻžāϰ āĻŽā§āϝāĻŧāĻžāĻĻ āĻŽāĻžāϤā§āϰ ā§Ģā§Ļ āĻŽāĻŋāϞāĻŋ-āϏā§āĻā§āύā§āĻĄ
queryCtx, cancel := context.WithTimeout(ctx, 50*time.Millisecond)
defer cancel() // āĻ
āĻŦāĻļā§āϝāĻ āĻāϞ āĻāϰāĻŦā§āύ
// ⧍. QueryContext āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύ
// āϝāĻĻāĻŋ ā§Ģā§Ļms-āĻāϰ āĻŽāϧā§āϝ⧠DB āĻāϤā§āϤāϰ āύāĻž āĻĻā§āϝāĻŧ, āĻāĻāĻŋ āĻ
āĻā§āĻŽā§āĻāĻŋāĻ āĻā§āϝāĻžāύā§āϏā§āϞ āĻšāĻŦā§
row := db.QueryContext(queryCtx, "SELECT name FROM users WHERE id=?", id)
// ... scan and return
}
ā§Ģ. Context Values: The Dark Side (āϏāϤāϰā§āĻāϤāĻž)
context.WithValue āĻā§āĻŦ āĻŦāĻŋāϤāϰā§āĻāĻŋāϤāĨ¤ āĻāĻāĻŋ āĻ
āύā§āĻāĻāĻž āĻā§āϞā§āĻŦāĻžāϞ āĻā§āϰāĻŋāϝāĻŧā§āĻŦāϞā§āϰ āĻŽāϤā§āĨ¤
â āϝāĻž āĻāĻāύ⧠Context-āĻ āϰāĻžāĻāĻŦā§āύ āύāĻž:
- Database Connection
- Logger objects
- Configuration
- āĻĢāĻžāĻāĻļāύā§āϰ āĻĒā§āϰā§ā§āĻāύā§ā§ āĻāϰā§āĻā§āĻŽā§āύā§āĻ (āϝā§āĻŽāύ
username,orderID)
â āϝāĻž Context-āĻ āϰāĻžāĻāϤ⧠āĻĒāĻžāϰā§āύ (Request Scoped Meta):
- Trace ID / Request ID (āϞāĻ āĻā§āϰā§āϏāĻŋāĻā§ā§āϰ āĻāύā§āϝ)
- User ID / Role ( āĻ āĻĨā§āύā§āĻāĻŋāĻā§āĻļāύ āĻŽāĻŋāĻĄāϞāĻā§ā§āϝāĻžāϰ āĻĨā§āĻā§)
- IP Address
Best Practice Code:
// Key-āĻāϰ āĻāύā§āϝ āĻāϞāĻžāĻĻāĻž type āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύ āϝāĻžāϤ⧠collision āύāĻž āĻšāϝāĻŧ
type key int
const userKey key = 1
// Value āϏā§āĻ āĻāϰāĻž
func WithUser(ctx context.Context, u *User) context.Context {
return context.WithValue(ctx, userKey, u)
}
// Value āĻŦā§āϰ āĻāϰāĻž
func UserFrom(ctx context.Context) (*User, bool) {
u, ok := ctx.Value(userKey).(*User)
return u, ok
}
ā§Ŧ. Advanced: Detached Context (Fire and Forget)
āĻŽāĻžāĻā§āĻŽāϧā§āϝ⧠āĻĒā§āϝāĻžāϰā§āύā§āĻ āϰāĻŋāĻā§ā§ā§āϏā§āĻ āĻļā§āώ āĻšā§ā§ āĻā§āϞā§āĻ āĻāĻŽāĻžāĻĻā§āϰ āĻāĻŋāĻā§ āĻāĻžāĻ (āϝā§āĻŽāύ: āϞāĻ āϏā§āĻ āĻāϰāĻž, āĻŽā§āĻā§āϰāĻŋāĻā§āϏ āĻĒāĻžāĻ āĻžāύā§) āĻāĻžāϞāĻŋā§ā§ āϝā§āϤ⧠āĻšā§āĨ¤ āϤāĻāύ WithoutCancel (Go 1.21+) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āĻšā§āĨ¤
func mainHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// āϏāĻžāϧāĻžāϰāĻŖ āĻāĻžāĻ
processData(ctx)
// āϰāĻŋāĻā§āϝāĻŧā§āϏā§āĻ āĻļā§āώ, āĻāĻŋāύā§āϤ⧠āĻāĻŽāϰāĻž āϞāĻ āϏā§āĻ āĻāϰāϤ⧠āĻāĻžāĻ
// āĻĒā§āϝāĻžāϰā§āύā§āĻ (ctx) āĻā§āϝāĻžāύāϏā§āϞ āĻšāϞā§āĻ āĻāĻāĻŋ āĻā§āϝāĻžāύāϏā§āϞ āĻšāĻŦā§ āύāĻž
go saveAuditLog(context.WithoutCancel(ctx))
}
đ Production Checklist for Context
āĻā§āĻĄ āϰāĻŋāĻāĻŋāĻ āĻāϰāĻžāϰ āϏāĻŽā§ āĻāĻ āĻĒā§ā§āύā§āĻāĻā§āϞ⧠āĻā§āĻ āĻāϰā§āύ:
- First Parameter:
ctxāĻāĻŋ āĻĢāĻžāĻāĻļāύā§āϰ āĻĒā§āϰāĻĨāĻŽ āĻāϰā§āĻā§āĻŽā§āύā§āĻ āĻšāĻŋāϏā§āĻŦā§ āĻāĻā§? (āϏā§āĻā§āϝāĻžāύā§āĻĄāĻžāϰā§āĻĄ āĻĒā§āϰā§āϝāĻžāĻāĻāĻŋāϏ)āĨ¤ - Struct Field:
ContextāĻāĻŋ āĻā§āύā§struct-āĻāϰ āĻā§āϤāϰ⧠āĻĢāĻŋāϞā§āĻĄ āĻšāĻŋāϏā§āĻŦā§ āϰāĻžāĻāĻž āĻšā§ā§āĻā§? (Never do this!)āĨ¤ Context āĻĒā§āϰāϤāĻŋāĻāĻŋ āĻĢāĻžāĻāĻļāύ āĻāϞ⧠āĻĒāĻžāϏ āĻāϰāϤ⧠āĻšā§āĨ¤ - Cancel Call:
WithTimeoutāĻŦāĻžWithCancelāĻāϞ āĻāϰāĻžāϰ āĻ āĻŋāĻ āĻĒāϰā§āĻdefer cancel()āĻĻā§āĻā§āĻž āĻšā§ā§āĻā§ āϤā§? (āύāĻž āĻšāϞ⧠āĻŽā§āĻŽāϰāĻŋ āϞāĻŋāĻ āĻšāĻŦā§)āĨ¤ - Nil Context: āĻā§āĻĨāĻžāĻ āĻāĻŋ
nilāĻĒāĻžāϏ āĻāϰāĻž āĻšāĻā§āĻā§?nilāĻāϰ āĻŦāĻĻāϞā§context.TODO()āĻŦāĻžcontext.Background()āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύāĨ¤ - Monitor:
select { case <-ctx.Done(): ... }āĻĻāĻŋā§ā§ āĻāĻŋ āϞāĻ āϰāĻžāύāĻŋāĻ āĻĒā§āϰāϏā§āϏ āĻŽāύāĻŋāĻāϰ āĻāϰāĻž āĻšāĻā§āĻā§?
đ Context vs Channels (āĻāύāĻĢāĻŋāĻāĻļāύ āĻĻā§āϰā§āĻāϰāĻŖ)
| āĻŦā§āĻļāĻŋāώā§āĻā§āϝ | Context | Channels |
|---|---|---|
| āĻŽā§āϞ āĻāĻžāĻ | Signaling & Lifecycle Management (āĻāĻāύ āĻāĻžāĻ āĻĨāĻžāĻŽāĻŦā§)āĨ¤ | Data Flow (āĻĄā§āĻāĻž āĻāĻĻāĻžāύ-āĻĒā§āϰāĻĻāĻžāύ)āĨ¤ |
| Data Types | āĻŽā§āĻāĻžāĻĄā§āĻāĻž (Request ID, Token)āĨ¤ | āĻ ā§āϝāĻžāĻĒā§āϞāĻŋāĻā§āĻļāύā§āϰ āĻāϏāϞ āĻĄā§āĻāĻž (Struct, Int, String)āĨ¤ |
| Direction | āĻāĻĒāϰ āĻĨā§āĻā§ āύāĻŋāĻā§ (Parent â Child)āĨ¤ | āĻĻā§āĻ āĻĻāĻŋāĻā§āĻ āĻšāϤ⧠āĻĒāĻžāϰ⧠(āĻāĻŋāύā§āϤ⧠āϏāĻžāϧāĻžāϰāĻŖāϤ Unidirectional āĻāĻžāϞā§)āĨ¤ |
đĄ Final Pro Tip for Interviews
āϝāĻĻāĻŋ āĻĒā§āϰāĻļā§āύ āĻāϰā§: âGo āϤ⧠Context āĻā§āύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻž āĻšā§?â
āĻāϤā§āϤāϰ: > âContext āĻŽā§āϞāϤ āϤāĻŋāύāĻāĻŋ āĻāĻžāĻā§āϰ āĻāύā§āϝ āĻŦā§āϝāĻŦāĻšā§āϤ āĻšāϝāĻŧ:
ā§§. Timeout & Cancellation Control (āϝāĻžāϤ⧠Goroutine leak āύāĻž āĻšāϝāĻŧ)āĨ¤ ⧍. Propagation (āĻĒā§āϝāĻžāϰā§āύā§āĻ āĻĒā§āϰāϏā§āϏ āĻŦāύā§āϧ āĻšāϞ⧠āĻāĻžāĻāϞā§āĻĄ āĻĒā§āϰāϏā§āϏāĻā§āϞā§āĻ āϝāĻžāϤ⧠āĻŦāύā§āϧ āĻšāϝāĻŧ)āĨ¤ ā§Š. Request Scoped Values āĻĒāĻžāϏ āĻāϰāĻž (āϝā§āĻŽāύ Trace ID)āĨ¤â