{"id":1090,"date":"2026-08-17T00:43:03","date_gmt":"2026-08-17T00:43:03","guid":{"rendered":"https:\/\/www.devopsschool.com\/tutorials\/?p=1090"},"modified":"2026-08-17T08:31:27","modified_gmt":"2026-08-17T08:31:27","slug":"go-concurrency-management-made-simple","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/tutorials\/go-concurrency-management-made-simple\/","title":{"rendered":"Go Concurrency Management Made Simple"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This tutorial covers:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><code>sync.WaitGroup<\/code><\/li>\n\n\n\n<li><code>sync.Mutex<\/code><\/li>\n\n\n\n<li>Goroutine leaks<\/li>\n\n\n\n<li><code>context.Context<\/code><\/li>\n\n\n\n<li>Cancellation<\/li>\n\n\n\n<li>Timeouts<\/li>\n\n\n\n<li>Graceful shutdown<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">The goal is:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>One concept \u2192 one purpose \u2192 one complete runnable example.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Every example is independent.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Save any example as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>main.go<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>go run main.go<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">0. First Understand the Big Picture<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">These concepts solve <strong>different concurrency problems<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Problem<\/th><th>Go tool\/concept<\/th><\/tr><\/thead><tbody><tr><td>Wait until goroutines finish<\/td><td><code>WaitGroup<\/code><\/td><\/tr><tr><td>Protect shared data<\/td><td><code>Mutex<\/code><\/td><\/tr><tr><td>Stop forgotten\/stuck goroutines<\/td><td>Leak prevention<\/td><\/tr><tr><td>Carry cancellation\/deadline information<\/td><td><code>context.Context<\/code><\/td><\/tr><tr><td>Tell running work to stop<\/td><td>Cancellation<\/td><\/tr><tr><td>Stop work after a time limit<\/td><td>Timeout<\/td><\/tr><tr><td>Stop the whole application cleanly<\/td><td>Graceful shutdown<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Mental model:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    A&#91;Concurrent Application]\n\n    A --&gt; B&#91;WaitGroup]\n    A --&gt; C&#91;Mutex]\n    A --&gt; D&#91;Context]\n\n    B --&gt; B1&#91;Wait for goroutines]\n\n    C --&gt; C1&#91;Protect shared data]\n\n    D --&gt; D1&#91;Cancellation]\n    D --&gt; D2&#91;Timeout]\n\n    D1 --&gt; E&#91;Stop goroutines safely]\n    D2 --&gt; E\n\n    E --&gt; F&#91;Graceful Shutdown]\n\n    A --&gt; G&#91;Prevent Goroutine Leaks]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The most important thing to remember:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>WaitGroup waits. Mutex protects. Context communicates when work should stop.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1. <code>sync.WaitGroup<\/code><\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A <code>WaitGroup<\/code> lets one goroutine wait until other goroutines have finished.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Think of it like a counter.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>3 workers started\n\ncounter = 3\n\nworker finishes \u2192 counter = 2\nworker finishes \u2192 counter = 1\nworker finishes \u2192 counter = 0\n\nmain can continue<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose <code>main()<\/code> starts three goroutines.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Without waiting, <code>main()<\/code> might finish before the goroutines finish.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A <code>WaitGroup<\/code> solves this.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use <code>WaitGroup<\/code> when:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>starting several goroutines<\/li>\n\n\n\n<li>you need to wait for all of them<\/li>\n\n\n\n<li>the program must not continue until they finish<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Common examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>processing several files<\/li>\n\n\n\n<li>running background jobs<\/li>\n\n\n\n<li>making several API requests<\/li>\n\n\n\n<li>starting multiple workers<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Three important operations:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wg.Add(1)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">One goroutine is starting.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wg.Done()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">One goroutine finished.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Finally:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wg.Wait()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Wait until everybody is finished.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Usually:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>main\n  \u2193\nstart goroutines\n  \u2193\nWaitGroup\n  \u2193\nwait\n  \u2193\ncontinue<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Complete Example<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n)\n\nfunc worker(id int, wg *sync.WaitGroup) {\n\n\t\/\/ Done() decreases the WaitGroup counter by 1.\n\t\/\/ defer makes sure it runs when worker finishes.\n\tdefer wg.Done()\n\n\tfmt.Println(\"Worker\", id, \"started\")\n\n\t\/\/ Simulate some work.\n\ttime.Sleep(500 * time.Millisecond)\n\n\tfmt.Println(\"Worker\", id, \"finished\")\n}\n\nfunc main() {\n\n\tvar wg sync.WaitGroup\n\n\t\/\/ Start 3 workers.\n\tfor i := 1; i &lt;= 3; i++ {\n\n\t\t\/\/ Tell WaitGroup:\n\t\t\/\/ one more goroutine is starting.\n\t\twg.Add(1)\n\n\t\tgo worker(i, &amp;wg)\n\t}\n\n\tfmt.Println(\"Main is waiting...\")\n\n\t\/\/ Wait until all workers call Done().\n\twg.Wait()\n\n\tfmt.Println(\"All workers finished\")\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Possible output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Main is waiting...\nWorker 1 started\nWorker 3 started\nWorker 2 started\nWorker 1 finished\nWorker 2 finished\nWorker 3 finished\nAll workers finished<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The worker order may change.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is normal.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Mental Model<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart LR\n    M&#91;main] --&gt; W1&#91;Worker 1]\n    M --&gt; W2&#91;Worker 2]\n    M --&gt; W3&#91;Worker 3]\n\n    W1 --&gt; WG&#91;WaitGroup]\n    W2 --&gt; WG\n    W3 --&gt; WG\n\n    WG --&gt; C&#91;main continues]<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Remember<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>WaitGroup<\/code>:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Waits for goroutines.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">It does <strong>not<\/strong> protect shared data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is the job of a <code>Mutex<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2. <code>sync.Mutex<\/code><\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A mutex protects shared data so that only one goroutine changes it at a time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mutex means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Mutual exclusion<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Think of a bathroom with one key.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Goroutine 1 gets key\n        \u2193\nchanges shared data\n        \u2193\nreturns key\n\nGoroutine 2 gets key\n        \u2193\nchanges shared data<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Only one enters the protected section at a time.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Why?<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine two goroutines execute:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>counter++<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">at the same time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>counter++<\/code> is not really one operation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Conceptually it involves:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>read counter\nadd 1\nwrite counter<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Two goroutines can interfere with each other.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This creates a:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>race condition<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">A mutex prevents that.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use a mutex when multiple goroutines access shared mutable data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>counters<\/li>\n\n\n\n<li>maps<\/li>\n\n\n\n<li>shared structs<\/li>\n\n\n\n<li>caches<\/li>\n\n\n\n<li>balances<\/li>\n\n\n\n<li>in-memory state<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Lock:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mu.Lock()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Modify protected data:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>counter++<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Unlock:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mu.Unlock()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Common pattern:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mu.Lock()\ndefer mu.Unlock()<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Put the mutex around the <strong>smallest section that accesses shared data<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Complete Example<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc main() {\n\n\tvar wg sync.WaitGroup\n\tvar mu sync.Mutex\n\n\tcounter := 0\n\n\t\/\/ Start 1000 goroutines.\n\tfor i := 0; i &lt; 1000; i++ {\n\n\t\twg.Add(1)\n\n\t\tgo func() {\n\n\t\t\tdefer wg.Done()\n\n\t\t\t\/\/ Only one goroutine can enter\n\t\t\t\/\/ this section at a time.\n\t\t\tmu.Lock()\n\n\t\t\tcounter++\n\n\t\t\tmu.Unlock()\n\t\t}()\n\t}\n\n\t\/\/ Wait for every goroutine.\n\twg.Wait()\n\n\tfmt.Println(\"Final counter:\", counter)\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Final counter: 1000<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What Happened?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">All 1000 goroutines want to modify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>counter<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The mutex changes this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Goroutine 1 \u2500\u2500\u2510\nGoroutine 2 \u2500\u2500\u253c\u2500\u2500&gt; counter\nGoroutine 3 \u2500\u2500\u2518<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">into:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Goroutine 1 \u2192 counter\n               \u2193\nGoroutine 2 \u2192 counter\n               \u2193\nGoroutine 3 \u2192 counter<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">One at a time.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">WaitGroup vs Mutex<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is extremely important.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>WaitGroup<\/th><th>Mutex<\/th><\/tr><\/thead><tbody><tr><td>Waits for goroutines<\/td><td>Protects shared data<\/td><\/tr><tr><td>Coordination<\/td><td>Synchronization<\/td><\/tr><tr><td><code>wg.Wait()<\/code><\/td><td><code>mu.Lock()<\/code><\/td><\/tr><tr><td>Does not prevent races<\/td><td>Prevents races on protected data<\/td><\/tr><tr><td>Used when goroutines must finish<\/td><td>Used when goroutines share mutable state<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Think:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WaitGroup = Are the workers finished?\n\nMutex = Who is allowed to touch this data?<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3. Goroutine Leaks<\/h1>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"536\" src=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/08\/image-1-1024x536.png\" alt=\"\" class=\"wp-image-1108\" srcset=\"https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/08\/image-1-1024x536.png 1024w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/08\/image-1-300x157.png 300w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/08\/image-1-768x402.png 768w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/08\/image-1-1536x804.png 1536w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/08\/image-1-820x430.png 820w, https:\/\/www.devopsschool.com\/tutorials\/wp-content\/uploads\/2026\/08\/image-1.png 1733w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A goroutine leak happens when a goroutine keeps running or waiting even though nobody needs it anymore.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The goroutine becomes stuck.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>main no longer needs worker\n\nBUT\n\nworker is still waiting forever<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why Is This Bad?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Every goroutine uses resources.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A few leaked goroutines may not matter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But imagine a server leaking one goroutine per request:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1 request     \u2192 1 leaked goroutine\n1,000 requests \u2192 1,000 leaked goroutines\n1,000,000      \u2192 big problem<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Over time this can consume memory and other resources.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When Do Leaks Happen?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Common situations:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>waiting forever on a channel<\/li>\n\n\n\n<li>trying to send when nobody receives<\/li>\n\n\n\n<li>infinite loops without a stop condition<\/li>\n\n\n\n<li>background goroutines that cannot be cancelled<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How Do We Prevent Them?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Give long-running goroutines a way to stop.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>done channel<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or, more commonly in real applications:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>context.Context<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Leak prevention matters especially in:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>servers<\/li>\n\n\n\n<li>workers<\/li>\n\n\n\n<li>background processing<\/li>\n\n\n\n<li>network applications<\/li>\n\n\n\n<li>long-running services<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Complete Example<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Here we create a producer that could run forever.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We give it a <code>done<\/code> channel so it knows when to stop.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\nfunc producer(done &lt;-chan struct{}, numbers chan&lt;- int, wg *sync.WaitGroup) {\n\n\tdefer wg.Done()\n\tdefer close(numbers)\n\n\tnumber := 1\n\n\tfor {\n\n\t\tselect {\n\n\t\t\/\/ Try to send another number.\n\t\tcase numbers &lt;- number:\n\n\t\t\tnumber++\n\n\t\t\/\/ Stop when main tells us\n\t\t\/\/ that the result is no longer needed.\n\t\tcase &lt;-done:\n\n\t\t\tfmt.Println(\"Producer stopped\")\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc main() {\n\n\tdone := make(chan struct{})\n\tnumbers := make(chan int)\n\n\tvar wg sync.WaitGroup\n\n\twg.Add(1)\n\n\tgo producer(done, numbers, &amp;wg)\n\n\t\/\/ We only need 3 numbers.\n\tfor i := 0; i &lt; 3; i++ {\n\n\t\tfmt.Println(\"Received:\", &lt;-numbers)\n\t}\n\n\t\/\/ Tell producer:\n\t\/\/ we don't need any more values.\n\tclose(done)\n\n\t\/\/ Make sure producer actually exits.\n\twg.Wait()\n\n\tfmt.Println(\"Program finished cleanly\")\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Received: 1\nReceived: 2\nReceived: 3\nProducer stopped\nProgram finished cleanly<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why Could This Leak?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine the producer only did:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>for {\n\tnumbers &lt;- number\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But <code>main()<\/code> stopped receiving.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The producer could become stuck trying to send.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead we gave it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>case &lt;-done:\n\treturn<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now it has an exit path.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Golden Rule<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Every long-running goroutine should answer this question:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>How will this goroutine stop?<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">If you cannot answer that question, examine the code carefully for a possible goroutine leak.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4. <code>context.Context<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\"><code>context<\/code> is one of the most important ideas in production Go.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The name makes it sound more complicated than it is.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A <code>context.Context<\/code> is an object passed through your functions that can carry:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>cancellation signals<\/li>\n\n\n\n<li>deadlines<\/li>\n\n\n\n<li>timeouts<\/li>\n\n\n\n<li>small pieces of request-scoped information<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Think:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Request\n   \u2193\nContext\n   \u2193\nFunction A\n   \u2193\nFunction B\n   \u2193\nFunction C<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The same context travels through the operation.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>HTTP request\n    \u2193\nservice function\n    \u2193\ndatabase function<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the user cancels the HTTP request, the database operation may no longer be needed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Context lets that cancellation information flow downward.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use context for operations that belong to a request or task.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Common examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>HTTP requests<\/li>\n\n\n\n<li>database calls<\/li>\n\n\n\n<li>API calls<\/li>\n\n\n\n<li>background jobs<\/li>\n\n\n\n<li>cancellation<\/li>\n\n\n\n<li>deadlines<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Usually the first parameter is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ctx context.Context<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func process(ctx context.Context) {\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then pass it down:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>process(ctx)<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Context usually flows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>caller\n  \u2193\nservice\n  \u2193\nrepository\n  \u2193\ndatabase\/API<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Complete Example<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This example uses context to pass request-scoped information through multiple functions.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\n\/\/ Define our own key type.\n\/\/ This helps avoid key collisions.\ntype contextKey string\n\nconst requestIDKey contextKey = \"requestID\"\n\nfunc databaseCall(ctx context.Context) {\n\n\t\/\/ Read request information from context.\n\trequestID := ctx.Value(requestIDKey)\n\n\tfmt.Println(\"Database received request ID:\", requestID)\n}\n\nfunc processRequest(ctx context.Context) {\n\n\tfmt.Println(\"Processing request\")\n\n\t\/\/ Pass the same context down.\n\tdatabaseCall(ctx)\n}\n\nfunc main() {\n\n\t\/\/ Start with a base context.\n\tctx := context.Background()\n\n\t\/\/ Add request-scoped information.\n\tctx = context.WithValue(\n\t\tctx,\n\t\trequestIDKey,\n\t\t\"REQ-123\",\n\t)\n\n\t\/\/ Pass context into our application.\n\tprocessRequest(ctx)\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Processing request\nDatabase received request ID: REQ-123<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Mental Model<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    A&#91;main creates Context]\n    A --&gt; B&#91;processRequest]\n    B --&gt; C&#91;databaseCall]\n\n    D&#91;Request ID] --&gt; A<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The context follows the operation.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Important<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Do not use context as a replacement for normal function parameters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Bad idea:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>username\npassword\nprice\nproduct ID<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">should normally be regular parameters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Context values are mainly useful for request-scoped metadata such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>request ID\ntrace ID<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The most important uses of context are actually:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>cancellation and timeouts<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">which we cover next.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">5. Cancellation<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cancellation means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Tell running work that it should stop.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>main\n \u2193\nworker running\n \u2193\nmain says CANCEL\n \u2193\nworker stops<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Sometimes work becomes unnecessary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Examples:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>user cancelled request<\/li>\n\n\n\n<li>application is shutting down<\/li>\n\n\n\n<li>another operation already succeeded<\/li>\n\n\n\n<li>task is no longer needed<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">We don&#8217;t want goroutines continuing useless work.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use cancellation for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>background workers<\/li>\n\n\n\n<li>HTTP requests<\/li>\n\n\n\n<li>database operations<\/li>\n\n\n\n<li>API calls<\/li>\n\n\n\n<li>long-running loops<\/li>\n\n\n\n<li>concurrent pipelines<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Create a cancellable context:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ctx, cancel := context.WithCancel(context.Background())<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Later:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cancel()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The worker watches:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ctx.Done()<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Usually:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>parent creates context\n        \u2193\nstarts worker\n        \u2193\nworker receives context\n        \u2193\nparent calls cancel()\n        \u2193\nworker exits<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Complete Example<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc worker(ctx context.Context) {\n\n\tfor {\n\n\t\tselect {\n\n\t\t\/\/ Simulate doing work repeatedly.\n\t\tcase &lt;-time.After(500 * time.Millisecond):\n\n\t\t\tfmt.Println(\"Worker is working...\")\n\n\t\t\/\/ Stop when context is cancelled.\n\t\tcase &lt;-ctx.Done():\n\n\t\t\tfmt.Println(\"Worker received cancellation\")\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc main() {\n\n\t\/\/ Create a context that can be cancelled.\n\tctx, cancel := context.WithCancel(\n\t\tcontext.Background(),\n\t)\n\n\t\/\/ Start worker.\n\tgo worker(ctx)\n\n\t\/\/ Let it work for a short time.\n\ttime.Sleep(1600 * time.Millisecond)\n\n\tfmt.Println(\"Main: cancel the worker\")\n\n\t\/\/ Send cancellation signal.\n\tcancel()\n\n\t\/\/ Give worker time to print its final message.\n\ttime.Sleep(200 * time.Millisecond)\n\n\tfmt.Println(\"Main finished\")\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Possible output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Worker is working...\nWorker is working...\nWorker is working...\nMain: cancel the worker\nWorker received cancellation\nMain finished<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Important Part<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Creation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ctx, cancel := context.WithCancel(...)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Send cancellation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cancel()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Receive cancellation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>case &lt;-ctx.Done():<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Mental model:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cancel()\n   |\n   v\nctx.Done()\n   |\n   v\nworker stops<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">6. Timeouts<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A timeout automatically cancels work after a certain amount of time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of manually saying:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>STOP<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">we say:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>You have 2 seconds.\n\nIf not finished:\nSTOP.<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">External operations can become slow or stuck.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>database server is slow<\/li>\n\n\n\n<li>API is not responding<\/li>\n\n\n\n<li>network request hangs<\/li>\n\n\n\n<li>background operation takes too long<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Without a timeout, your program may wait far longer than you intended.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use timeouts around operations that should have a maximum duration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Especially:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>API calls<\/li>\n\n\n\n<li>database calls<\/li>\n\n\n\n<li>network calls<\/li>\n\n\n\n<li>external services<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>context.WithTimeout()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ctx, cancel := context.WithTimeout(\n\tcontext.Background(),\n\t2*time.Second,\n)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Always call:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>defer cancel()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">to release context resources when you are done.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Timeouts usually belong at the boundary where you know:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">This operation should not take longer than X.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Complete Example<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n)\n\nfunc slowOperation(ctx context.Context) {\n\n\tselect {\n\n\t\/\/ Pretend the operation takes 5 seconds.\n\tcase &lt;-time.After(5 * time.Second):\n\n\t\tfmt.Println(\"Operation completed\")\n\n\t\/\/ Context finishes first.\n\tcase &lt;-ctx.Done():\n\n\t\tfmt.Println(\"Operation stopped:\", ctx.Err())\n\t}\n}\n\nfunc main() {\n\n\t\/\/ Allow the operation only 2 seconds.\n\tctx, cancel := context.WithTimeout(\n\t\tcontext.Background(),\n\t\t2*time.Second,\n\t)\n\n\t\/\/ Always release context resources.\n\tdefer cancel()\n\n\tslowOperation(ctx)\n\n\tfmt.Println(\"Main finished\")\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After about two seconds:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Operation stopped: context deadline exceeded\nMain finished<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What Happened?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The operation wanted:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>5 seconds<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But the context allowed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>2 seconds<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>0 sec\n |\n1 sec\n |\n2 sec ---- TIMEOUT\n |\nX operation stopped<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Cancellation vs Timeout<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These are closely related.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cancellation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You decide when to stop:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cancel()<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Timeout<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Go automatically stops after a duration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>context.WithTimeout(...)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Think:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Cancellation = Stop when I say so.\n\nTimeout = Stop when the clock says so.<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">7. Graceful Shutdown<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now all the previous ideas come together.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Graceful shutdown means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Stop accepting\/starting work, tell running goroutines to stop, wait for them, and then exit cleanly.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>KILL PROGRAM<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">we want:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Shutdown requested\n       \u2193\nTell workers to stop\n       \u2193\nWorkers clean up\n       \u2193\nWait for workers\n       \u2193\nExit<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine your application is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>writing a file<\/li>\n\n\n\n<li>processing a message<\/li>\n\n\n\n<li>updating data<\/li>\n\n\n\n<li>handling a request<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If the process immediately disappears, work may be interrupted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Graceful shutdown gives your application a chance to clean up.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">When?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use graceful shutdown for long-running applications such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>web servers<\/li>\n\n\n\n<li>API servers<\/li>\n\n\n\n<li>workers<\/li>\n\n\n\n<li>queue consumers<\/li>\n\n\n\n<li>background services<\/li>\n\n\n\n<li>microservices<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A common Go pattern combines:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>OS signal\n+\ncontext\n+\nWaitGroup<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Flow:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    A&#91;Application Running]\n    A --&gt; B&#91;Ctrl+C \/ OS Signal]\n    B --&gt; C&#91;Cancel Context]\n    C --&gt; D&#91;Workers see ctx.Done]\n    D --&gt; E&#91;Workers Stop]\n    E --&gt; F&#91;WaitGroup Finishes]\n    F --&gt; G&#91;Application Exits]<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Where?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Usually inside your application&#8217;s <code>main()<\/code> function.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Complete Example<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Copy and run this program.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then press:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Ctrl+C<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">to stop it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os\/signal\"\n\t\"sync\"\n\t\"time\"\n)\n\nfunc worker(ctx context.Context, wg *sync.WaitGroup) {\n\n\tdefer wg.Done()\n\n\tticker := time.NewTicker(1 * time.Second)\n\n\t\/\/ Always stop ticker when worker exits.\n\tdefer ticker.Stop()\n\n\tfor {\n\n\t\tselect {\n\n\t\t\/\/ Do some regular background work.\n\t\tcase &lt;-ticker.C:\n\n\t\t\tfmt.Println(\"Worker: processing...\")\n\n\t\t\/\/ Shutdown requested.\n\t\tcase &lt;-ctx.Done():\n\n\t\t\tfmt.Println(\"Worker: cleaning up...\")\n\t\t\ttime.Sleep(500 * time.Millisecond)\n\n\t\t\tfmt.Println(\"Worker: stopped\")\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc main() {\n\n\t\/\/ Create a context that is cancelled\n\t\/\/ when Ctrl+C is pressed.\n\tctx, stop := signal.NotifyContext(\n\t\tcontext.Background(),\n\t\tos.Interrupt,\n\t)\n\n\tdefer stop()\n\n\tvar wg sync.WaitGroup\n\n\twg.Add(1)\n\n\tgo worker(ctx, &amp;wg)\n\n\tfmt.Println(\"Application running\")\n\tfmt.Println(\"Press Ctrl+C to stop\")\n\n\t\/\/ Wait until Ctrl+C cancels the context.\n\t&lt;-ctx.Done()\n\n\tfmt.Println(\"Main: shutdown requested\")\n\n\t\/\/ Wait for worker cleanup.\n\twg.Wait()\n\n\tfmt.Println(\"Application stopped cleanly\")\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Application running\nPress Ctrl+C to stop\nWorker: processing...\nWorker: processing...\nWorker: processing...\n^C\nMain: shutdown requested\nWorker: cleaning up...\nWorker: stopped\nApplication stopped cleanly<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">How Graceful Shutdown Works<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The key line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ctx, stop := signal.NotifyContext(\n\tcontext.Background(),\n\tos.Interrupt,\n)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Cancel this context when the application receives Ctrl+C.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Our worker already understands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>case &lt;-ctx.Done():<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So the sequence becomes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Ctrl+C\n   \u2193\ncontext cancelled\n   \u2193\nctx.Done()\n   \u2193\nworker cleans up\n   \u2193\nworker returns\n   \u2193\nwg.Done()\n   \u2193\nwg.Wait() finishes\n   \u2193\nprogram exits<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is why <code>Context<\/code> + <code>WaitGroup<\/code> work very well together.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Compare All Seven Concepts<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Concept<\/th><th>Main Job<\/th><th>Typical Question It Answers<\/th><th>Important API<\/th><\/tr><\/thead><tbody><tr><td><code>WaitGroup<\/code><\/td><td>Wait for goroutines<\/td><td>Have all workers finished?<\/td><td><code>Add<\/code>, <code>Done<\/code>, <code>Wait<\/code><\/td><\/tr><tr><td><code>Mutex<\/code><\/td><td>Protect shared data<\/td><td>Who can modify this data now?<\/td><td><code>Lock<\/code>, <code>Unlock<\/code><\/td><\/tr><tr><td>Goroutine leak prevention<\/td><td>Make goroutines able to exit<\/td><td>Can this goroutine ever get stuck forever?<\/td><td><code>done<\/code>, <code>context<\/code><\/td><\/tr><tr><td><code>Context<\/code><\/td><td>Carry task lifecycle information<\/td><td>Does this operation still matter?<\/td><td><code>context.Context<\/code><\/td><\/tr><tr><td>Cancellation<\/td><td>Stop work manually<\/td><td>Should this work stop now?<\/td><td><code>WithCancel<\/code>, <code>cancel()<\/code><\/td><\/tr><tr><td>Timeout<\/td><td>Stop work after a duration<\/td><td>Has this taken too long?<\/td><td><code>WithTimeout<\/code><\/td><\/tr><tr><td>Graceful shutdown<\/td><td>Stop the application safely<\/td><td>How do we shut everything down cleanly?<\/td><td>signal + context + <code>WaitGroup<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">What Each One Does NOT Do<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This table is very useful for avoiding confusion.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Concept<\/th><th>Does<\/th><th>Does NOT<\/th><\/tr><\/thead><tbody><tr><td>WaitGroup<\/td><td>Wait for goroutines<\/td><td>Protect variables<\/td><\/tr><tr><td>Mutex<\/td><td>Protect shared variables<\/td><td>Stop goroutines<\/td><\/tr><tr><td>Leak prevention<\/td><td>Ensure goroutines can exit<\/td><td>Automatically protect shared data<\/td><\/tr><tr><td>Context<\/td><td>Carries lifecycle signals<\/td><td>Automatically kill goroutines<\/td><\/tr><tr><td>Cancellation<\/td><td>Signals work to stop<\/td><td>Force goroutines to stop<\/td><\/tr><tr><td>Timeout<\/td><td>Signals cancellation after time<\/td><td>Guarantee a function obeys it<\/td><\/tr><tr><td>Graceful shutdown<\/td><td>Coordinates application shutdown<\/td><td>Instantly terminate everything<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Notice something important:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Context does not physically kill a goroutine.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">The goroutine must cooperate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>select {\ncase &lt;-ctx.Done():\n\treturn\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The worker chooses to exit when it receives the signal.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">WaitGroup vs Mutex<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Probably the most common beginner confusion:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WaitGroup<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Mutex<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">have completely different jobs.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th><\/th><th>WaitGroup<\/th><th>Mutex<\/th><\/tr><\/thead><tbody><tr><td>Purpose<\/td><td>Wait<\/td><td>Protect<\/td><\/tr><tr><td>Concern<\/td><td>Goroutine completion<\/td><td>Shared data<\/td><\/tr><tr><td>Main call<\/td><td><code>Wait()<\/code><\/td><td><code>Lock()<\/code><\/td><\/tr><tr><td>Used with <code>Done()<\/code><\/td><td>Yes<\/td><td>No<\/td><\/tr><tr><td>Prevents race conditions<\/td><td>No<\/td><td>Yes<\/td><\/tr><tr><td>Stops goroutines<\/td><td>No<\/td><td>No<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Remember:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>WaitGroup manages completion. Mutex manages access.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Context vs Cancellation vs Timeout<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">These three are closely connected.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Think of <code>Context<\/code> as the <strong>communication system<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Cancellation and timeout are things communicated through that system.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>flowchart TD\n    C&#91;Context]\n\n    C --&gt; A&#91;Manual Cancellation]\n    C --&gt; B&#91;Timeout]\n\n    A --&gt; D&#91;ctx.Done closes]\n    B --&gt; D\n\n    D --&gt; E&#91;Worker detects signal]\n    E --&gt; F&#91;Worker stops]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Comparison:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Context<\/th><th>Cancellation<\/th><th>Timeout<\/th><\/tr><\/thead><tbody><tr><td>The mechanism<\/td><td>Manual stop signal<\/td><td>Automatic stop signal<\/td><\/tr><tr><td>Passed between functions<\/td><td>Yes<\/td><td>Uses context<\/td><\/tr><tr><td>Time based<\/td><td>Not necessarily<\/td><td>No<\/td><\/tr><tr><td>Typical API<\/td><td><code>context.Context<\/code><\/td><td><code>WithCancel<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Cancellation vs Goroutine Leak Prevention<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Cancellation is one of the main ways to prevent leaks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Without cancellation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>worker\n  \u2193\nloops forever\n  \u2193\nnobody needs it\n  \u2193\nstill running<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With cancellation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>worker\n  \u2193\nctx.Done()\n  \u2193\nreturn<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">So:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Cancellation provides an exit door for a goroutine.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">WaitGroup + Context<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">These two are often used together.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Context says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Stop working.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">WaitGroup says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">I will wait until you have actually stopped.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Example flow:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cancel()\n   \u2193\nWorker A stops \u2500\u2510\nWorker B stops \u2500\u253c\u2500\u2500&gt; WaitGroup\nWorker C stops \u2500\u2518\n                    \u2193\n               main continues<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s an extremely common production Go pattern.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Mutex + WaitGroup<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">These two are also often used together.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose 100 goroutines modify a counter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mutex:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>protects counter<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">WaitGroup:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>waits for all 100 goroutines<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">They solve different parts of the same problem.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Graceful Shutdown Uses Everything Together<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">In a real service you may eventually have:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Application\n      |\n      +------ Worker 1\n      |\n      +------ Worker 2\n      |\n      +------ Worker 3<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then shutdown happens:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Ctrl+C\n   \u2193\nContext cancelled\n   \u2193\nWorkers receive cancellation\n   \u2193\nWorkers finish current cleanup\n   \u2193\nWaitGroup waits\n   \u2193\nApplication exits<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A mutex may additionally protect any shared state those workers use.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">The Best Learning Order<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Learn these concepts in this order:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. WaitGroup\n      \u2193\n2. Mutex\n      \u2193\n3. Goroutine leaks\n      \u2193\n4. Context\n      \u2193\n5. Cancellation\n      \u2193\n6. Timeout\n      \u2193\n7. Graceful shutdown<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Why this order?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because the concepts build naturally.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Step 1 \u2014 WaitGroup<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Learn:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wg.Add(1)\n\ngo func() {\n\tdefer wg.Done()\n}()\n\nwg.Wait()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Meaning:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Start\n\u2193\nWork\n\u2193\nFinish\n\u2193\nWait<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Step 2 \u2014 Mutex<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Learn:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mu.Lock()\n\nsharedData++\n\nmu.Unlock()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Meaning:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>only one goroutine here<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Step 3 \u2014 Goroutine Leak Prevention<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Learn to ask:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">How does this goroutine exit?<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Long-running goroutines should normally have something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>case &lt;-done:\n\treturn<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>case &lt;-ctx.Done():\n\treturn<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Step 4 \u2014 Context<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Learn:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>func work(ctx context.Context)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and pass it downward:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>main\n \u2193\nservice(ctx)\n \u2193\ndatabase(ctx)<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Step 5 \u2014 Cancellation<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Learn:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ctx, cancel := context.WithCancel(\n\tcontext.Background(),\n)\n\ncancel()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Worker:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>case &lt;-ctx.Done():\n\treturn<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Step 6 \u2014 Timeout<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Learn:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ctx, cancel := context.WithTimeout(\n\tcontext.Background(),\n\t2*time.Second,\n)\n\ndefer cancel()<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Meaning:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>You have 2 seconds.<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Step 7 \u2014 Graceful Shutdown<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Combine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>OS Signal\n   +\nContext\n   +\nWaitGroup<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">to cleanly stop your application.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Final Cheat Sheet<\/h1>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>If you want to&#8230;<\/th><th>Use<\/th><\/tr><\/thead><tbody><tr><td>Wait for goroutines<\/td><td><code>sync.WaitGroup<\/code><\/td><\/tr><tr><td>Protect shared state<\/td><td><code>sync.Mutex<\/code><\/td><\/tr><tr><td>Prevent stuck background goroutines<\/td><td>Cancellation \/ exit signal<\/td><\/tr><tr><td>Pass cancellation through your program<\/td><td><code>context.Context<\/code><\/td><\/tr><tr><td>Stop something manually<\/td><td><code>context.WithCancel<\/code><\/td><\/tr><tr><td>Stop something after N seconds<\/td><td><code>context.WithTimeout<\/code><\/td><\/tr><tr><td>Stop your whole service cleanly<\/td><td>Signal + Context + WaitGroup<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">The Seven Concepts in One Sentence Each<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">WaitGroup<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Wait until a group of goroutines has finished.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>wg.Wait()<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Mutex<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Allow only one goroutine at a time to access protected shared data.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>mu.Lock()\nmu.Unlock()<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Goroutine Leak<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">A goroutine that continues waiting or running when it should have stopped.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Always ask:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>How does this goroutine exit?<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Context<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Carries cancellation, deadline, and request lifecycle information through your program.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>func work(ctx context.Context)<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Cancellation<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Manually tell running work that it should stop.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>cancel()<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Timeout<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Automatically tell work to stop when it takes too long.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>context.WithTimeout(...)<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Graceful Shutdown<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Tell the application to stop, allow workers to clean up, wait for them, and then exit.<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>Signal\n  \u2193\nCancel\n  \u2193\nCleanup\n  \u2193\nWait\n  \u2193\nExit<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">The Most Important Mental Model<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">If you remember only this section, remember:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WaitGroup\n    =\n\"Wait until everyone is done.\"\n\n\nMutex\n    =\n\"Only one person can touch this.\"\n\n\nGoroutine leak prevention\n    =\n\"Every worker needs an exit door.\"\n\n\nContext\n    =\n\"Pass lifecycle information through the work.\"\n\n\nCancellation\n    =\n\"Stop when I tell you.\"\n\n\nTimeout\n    =\n\"Stop when time runs out.\"\n\n\nGraceful shutdown\n    =\n\"Tell everyone to stop, wait for them, then exit.\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And the most useful overall relationship is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Context tells goroutines WHEN to stop.\n\nGoroutines must cooperate and actually stop.\n\nWaitGroup tells main WHEN they have stopped.\n\nMutex protects shared data WHILE they are running.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Once this relationship becomes clear, Go concurrency management becomes much easier to reason about.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial covers: The goal is: One concept \u2192 one purpose \u2192 one complete runnable example. Every example is independent. Save any example as: and run: 0&#8230;. <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1090","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1090","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/comments?post=1090"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1090\/revisions"}],"predecessor-version":[{"id":1109,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1090\/revisions\/1109"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/media?parent=1090"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/categories?post=1090"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/tags?post=1090"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}