Context Cancellation, Timeout & Deadline
āĻāϤāĻŦāĻžāϰ āĻāĻŽāϰāĻž select āĻĻāĻŋā§ā§ āĻāĻāĻžāϧāĻŋāĻ āĻā§āϝāĻžāύā§āϞ āĻšā§āϝāĻžāύā§āĻĄā§āϞ āĻāϰāĻž āĻļāĻŋāĻā§āĻāĻŋāĨ¤ āĻāĻ āĻāĻŽāϰāĻž āĻļāĻŋāĻāĻŦā§ goroutine-āĻĻā§āϰ control āĻāϰāĻžāϰ āϏāĻŦāĻā§āϝāĻŧā§ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖ āĻāĻŦāĻ āĻļāĻā§āϤāĻŋāĻļāĻžāϞ⧠āĻā§āϞ: contextāĨ¤
đ§ 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 āĻšā§ |