[{"data":1,"prerenderedAt":2959},["ShallowReactive",2],{"page-\u002Fgo\u002F20-context":3},{"id":4,"title":5,"body":6,"description":2952,"extension":2953,"meta":2954,"navigation":140,"path":2955,"seo":2956,"stem":2957,"__hash__":2958},"content\u002Fgo\u002F20-context.md","20 — Context",{"type":7,"value":8,"toc":2946},"minimark",[9,13,27,32,2942],[10,11,5],"h1",{"id":12},"_20-context",[14,15,16,17,21,22,26],"p",{},"The ",[18,19,20],"code",{},"context"," package is Go's mechanism for ",[23,24,25],"strong",{},"cancellation, deadlines, and request-scoped values"," across API boundaries and goroutines.",[28,29,31],"h2",{"id":30},"the-context-tree","The Context Tree",[33,34,36,302,309,2809,2925,2929],"code-wrapper",{"language":35},"go",[37,38,42],"pre",{"className":39,"code":40,"language":35,"meta":41,"style":41},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F ┌──────────────────────────────────────────────────────────────────────┐\n\u002F\u002F │ Contexts form a TREE:                                                │\n\u002F\u002F │                                                                      │\n\u002F\u002F │   context.Background()  (root, never canceled, no deadline)         │\n\u002F\u002F │       ├── WithCancel(ctx)  → child1 (canceled when cancel() called)│\n\u002F\u002F │       ├── WithTimeout(ctx, 5s) → child2 (canceled at 5s)            │\n\u002F\u002F │       │       └── WithValue(child2, key, val) → child3              │\n\u002F\u002F │       └── WithDeadline(ctx, t) → child4                             │\n\u002F\u002F │                                                                      │\n\u002F\u002F │ Canceling a parent cancels ALL children (and their children).       │\n\u002F\u002F │ Canceling a child does NOT affect the parent or siblings.           │\n\u002F\u002F │                                                                      │\n\u002F\u002F │ ctx.Done() returns a channel closed when the context is canceled    │\n\u002F\u002F │   or times out. ctx.Err() returns the reason.                       │\n\u002F\u002F └──────────────────────────────────────────────────────────────────────┘\n\nfunc treeDemo() {\n    root, cancel := context.WithCancel(context.Background())\n    defer cancel()  \u002F\u002F ✅ always cancel to release resources\n\n    child, cancelChild := context.WithTimeout(root, 5*time.Second)\n    defer cancelChild()\n\n    grandchild, _ := context.WithValue(child, \"userID\", 42)\n    \u002F\u002F Canceling root cancels child AND grandchild.\n    \u002F\u002F Canceling child cancels grandchild but NOT root.\n    _ = grandchild\n}\n","",[18,43,44,53,59,65,71,77,83,89,95,100,106,112,117,123,129,135,142,157,181,196,201,227,238,243,272,278,284,296],{"__ignoreMap":41},[45,46,49],"span",{"class":47,"line":48},"line",1,[45,50,52],{"class":51},"sdCPZ","\u002F\u002F ┌──────────────────────────────────────────────────────────────────────┐\n",[45,54,56],{"class":47,"line":55},2,[45,57,58],{"class":51},"\u002F\u002F │ Contexts form a TREE:                                                │\n",[45,60,62],{"class":47,"line":61},3,[45,63,64],{"class":51},"\u002F\u002F │                                                                      │\n",[45,66,68],{"class":47,"line":67},4,[45,69,70],{"class":51},"\u002F\u002F │   context.Background()  (root, never canceled, no deadline)         │\n",[45,72,74],{"class":47,"line":73},5,[45,75,76],{"class":51},"\u002F\u002F │       ├── WithCancel(ctx)  → child1 (canceled when cancel() called)│\n",[45,78,80],{"class":47,"line":79},6,[45,81,82],{"class":51},"\u002F\u002F │       ├── WithTimeout(ctx, 5s) → child2 (canceled at 5s)            │\n",[45,84,86],{"class":47,"line":85},7,[45,87,88],{"class":51},"\u002F\u002F │       │       └── WithValue(child2, key, val) → child3              │\n",[45,90,92],{"class":47,"line":91},8,[45,93,94],{"class":51},"\u002F\u002F │       └── WithDeadline(ctx, t) → child4                             │\n",[45,96,98],{"class":47,"line":97},9,[45,99,64],{"class":51},[45,101,103],{"class":47,"line":102},10,[45,104,105],{"class":51},"\u002F\u002F │ Canceling a parent cancels ALL children (and their children).       │\n",[45,107,109],{"class":47,"line":108},11,[45,110,111],{"class":51},"\u002F\u002F │ Canceling a child does NOT affect the parent or siblings.           │\n",[45,113,115],{"class":47,"line":114},12,[45,116,64],{"class":51},[45,118,120],{"class":47,"line":119},13,[45,121,122],{"class":51},"\u002F\u002F │ ctx.Done() returns a channel closed when the context is canceled    │\n",[45,124,126],{"class":47,"line":125},14,[45,127,128],{"class":51},"\u002F\u002F │   or times out. ctx.Err() returns the reason.                       │\n",[45,130,132],{"class":47,"line":131},15,[45,133,134],{"class":51},"\u002F\u002F └──────────────────────────────────────────────────────────────────────┘\n",[45,136,138],{"class":47,"line":137},16,[45,139,141],{"emptyLinePlaceholder":140},true,"\n",[45,143,145,149,153],{"class":47,"line":144},17,[45,146,148],{"class":147},"svdQ7","func",[45,150,152],{"class":151},"sIsaT"," treeDemo",[45,154,156],{"class":155},"ssxIu","() {\n",[45,158,160,163,166,169,172,175,178],{"class":47,"line":159},18,[45,161,162],{"class":155},"    root, cancel ",[45,164,165],{"class":147},":=",[45,167,168],{"class":155}," context.",[45,170,171],{"class":151},"WithCancel",[45,173,174],{"class":155},"(context.",[45,176,177],{"class":151},"Background",[45,179,180],{"class":155},"())\n",[45,182,184,187,190,193],{"class":47,"line":183},19,[45,185,186],{"class":147},"    defer",[45,188,189],{"class":151}," cancel",[45,191,192],{"class":155},"()  ",[45,194,195],{"class":51},"\u002F\u002F ✅ always cancel to release resources\n",[45,197,199],{"class":47,"line":198},20,[45,200,141],{"emptyLinePlaceholder":140},[45,202,204,207,209,211,214,217,221,224],{"class":47,"line":203},21,[45,205,206],{"class":155},"    child, cancelChild ",[45,208,165],{"class":147},[45,210,168],{"class":155},[45,212,213],{"class":151},"WithTimeout",[45,215,216],{"class":155},"(root, ",[45,218,220],{"class":219},"snvgF","5",[45,222,223],{"class":147},"*",[45,225,226],{"class":155},"time.Second)\n",[45,228,230,232,235],{"class":47,"line":229},22,[45,231,186],{"class":147},[45,233,234],{"class":151}," cancelChild",[45,236,237],{"class":155},"()\n",[45,239,241],{"class":47,"line":240},23,[45,242,141],{"emptyLinePlaceholder":140},[45,244,246,249,251,253,256,259,263,266,269],{"class":47,"line":245},24,[45,247,248],{"class":155},"    grandchild, _ ",[45,250,165],{"class":147},[45,252,168],{"class":155},[45,254,255],{"class":151},"WithValue",[45,257,258],{"class":155},"(child, ",[45,260,262],{"class":261},"sJ6F3","\"userID\"",[45,264,265],{"class":155},", ",[45,267,268],{"class":219},"42",[45,270,271],{"class":155},")\n",[45,273,275],{"class":47,"line":274},25,[45,276,277],{"class":51},"    \u002F\u002F Canceling root cancels child AND grandchild.\n",[45,279,281],{"class":47,"line":280},26,[45,282,283],{"class":51},"    \u002F\u002F Canceling child cancels grandchild but NOT root.\n",[45,285,287,290,293],{"class":47,"line":286},27,[45,288,289],{"class":155},"    _ ",[45,291,292],{"class":147},"=",[45,294,295],{"class":155}," grandchild\n",[45,297,299],{"class":47,"line":298},28,[45,300,301],{"class":155},"}\n",[28,303,16,305,308],{"id":304},"the-cancel-leak-the-1-context-bug",[18,306,307],{},"cancel"," Leak — The #1 Context Bug",[33,310,311,594,598],{"language":35},[37,312,314],{"className":39,"code":313,"language":35,"meta":41,"style":41},"\u002F\u002F ❌ ANTI-PATTERN: not calling cancel — leaks the timer (and goroutine)\nfunc leakyFetch(url string) (*http.Response, error) {\n    ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)\n    \u002F\u002F ⚠️ cancel is discarded — the timer runs for 5 seconds even if the\n    \u002F\u002F request completes in 100ms. Each call leaks a timer goroutine.\n    return http.Get(url)  \u002F\u002F not using ctx anyway — double bad\n}\n\n\u002F\u002F ✅ CORRECT: always defer cancel()\nfunc goodFetch(ctx context.Context, url string) (*http.Response, error) {\n    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n    defer cancel()  \u002F\u002F ✅ releases the timer immediately when we return\n\n    req, err := http.NewRequestWithContext(ctx, \"GET\", url, nil)\n    if err != nil {\n        return nil, err\n    }\n    return http.DefaultClient.Do(req)\n}\n\n\u002F\u002F ⚠️ Even if the operation completes successfully, you MUST call cancel.\n\u002F\u002F WithTimeout\u002FWithDeadline allocate a timer goroutine. cancel() stops it.\n\u002F\u002F Without cancel, the timer lives until the deadline, leaking resources.\n",[18,315,316,321,360,384,389,394,411,415,419,424,466,486,497,501,526,543,553,558,571,575,579,584,589],{"__ignoreMap":41},[45,317,318],{"class":47,"line":48},[45,319,320],{"class":51},"\u002F\u002F ❌ ANTI-PATTERN: not calling cancel — leaks the timer (and goroutine)\n",[45,322,323,325,328,331,335,338,341,343,346,349,352,354,357],{"class":47,"line":55},[45,324,148],{"class":147},[45,326,327],{"class":151}," leakyFetch",[45,329,330],{"class":155},"(",[45,332,334],{"class":333},"sCrzJ","url",[45,336,337],{"class":147}," string",[45,339,340],{"class":155},") (",[45,342,223],{"class":147},[45,344,345],{"class":151},"http",[45,347,348],{"class":155},".",[45,350,351],{"class":151},"Response",[45,353,265],{"class":155},[45,355,356],{"class":147},"error",[45,358,359],{"class":155},") {\n",[45,361,362,365,367,369,371,373,375,378,380,382],{"class":47,"line":61},[45,363,364],{"class":155},"    ctx, _ ",[45,366,165],{"class":147},[45,368,168],{"class":155},[45,370,213],{"class":151},[45,372,174],{"class":155},[45,374,177],{"class":151},[45,376,377],{"class":155},"(), ",[45,379,220],{"class":219},[45,381,223],{"class":147},[45,383,226],{"class":155},[45,385,386],{"class":47,"line":67},[45,387,388],{"class":51},"    \u002F\u002F ⚠️ cancel is discarded — the timer runs for 5 seconds even if the\n",[45,390,391],{"class":47,"line":73},[45,392,393],{"class":51},"    \u002F\u002F request completes in 100ms. Each call leaks a timer goroutine.\n",[45,395,396,399,402,405,408],{"class":47,"line":79},[45,397,398],{"class":147},"    return",[45,400,401],{"class":155}," http.",[45,403,404],{"class":151},"Get",[45,406,407],{"class":155},"(url)  ",[45,409,410],{"class":51},"\u002F\u002F not using ctx anyway — double bad\n",[45,412,413],{"class":47,"line":85},[45,414,301],{"class":155},[45,416,417],{"class":47,"line":91},[45,418,141],{"emptyLinePlaceholder":140},[45,420,421],{"class":47,"line":97},[45,422,423],{"class":51},"\u002F\u002F ✅ CORRECT: always defer cancel()\n",[45,425,426,428,431,433,436,439,441,444,446,448,450,452,454,456,458,460,462,464],{"class":47,"line":102},[45,427,148],{"class":147},[45,429,430],{"class":151}," goodFetch",[45,432,330],{"class":155},[45,434,435],{"class":333},"ctx",[45,437,438],{"class":151}," context",[45,440,348],{"class":155},[45,442,443],{"class":151},"Context",[45,445,265],{"class":155},[45,447,334],{"class":333},[45,449,337],{"class":147},[45,451,340],{"class":155},[45,453,223],{"class":147},[45,455,345],{"class":151},[45,457,348],{"class":155},[45,459,351],{"class":151},[45,461,265],{"class":155},[45,463,356],{"class":147},[45,465,359],{"class":155},[45,467,468,471,473,475,477,480,482,484],{"class":47,"line":108},[45,469,470],{"class":155},"    ctx, cancel ",[45,472,165],{"class":147},[45,474,168],{"class":155},[45,476,213],{"class":151},[45,478,479],{"class":155},"(ctx, ",[45,481,220],{"class":219},[45,483,223],{"class":147},[45,485,226],{"class":155},[45,487,488,490,492,494],{"class":47,"line":114},[45,489,186],{"class":147},[45,491,189],{"class":151},[45,493,192],{"class":155},[45,495,496],{"class":51},"\u002F\u002F ✅ releases the timer immediately when we return\n",[45,498,499],{"class":47,"line":119},[45,500,141],{"emptyLinePlaceholder":140},[45,502,503,506,508,510,513,515,518,521,524],{"class":47,"line":125},[45,504,505],{"class":155},"    req, err ",[45,507,165],{"class":147},[45,509,401],{"class":155},[45,511,512],{"class":151},"NewRequestWithContext",[45,514,479],{"class":155},[45,516,517],{"class":261},"\"GET\"",[45,519,520],{"class":155},", url, ",[45,522,523],{"class":219},"nil",[45,525,271],{"class":155},[45,527,528,531,534,537,540],{"class":47,"line":131},[45,529,530],{"class":147},"    if",[45,532,533],{"class":155}," err ",[45,535,536],{"class":147},"!=",[45,538,539],{"class":219}," nil",[45,541,542],{"class":155}," {\n",[45,544,545,548,550],{"class":47,"line":137},[45,546,547],{"class":147},"        return",[45,549,539],{"class":219},[45,551,552],{"class":155},", err\n",[45,554,555],{"class":47,"line":144},[45,556,557],{"class":155},"    }\n",[45,559,560,562,565,568],{"class":47,"line":159},[45,561,398],{"class":147},[45,563,564],{"class":155}," http.DefaultClient.",[45,566,567],{"class":151},"Do",[45,569,570],{"class":155},"(req)\n",[45,572,573],{"class":47,"line":183},[45,574,301],{"class":155},[45,576,577],{"class":47,"line":198},[45,578,141],{"emptyLinePlaceholder":140},[45,580,581],{"class":47,"line":203},[45,582,583],{"class":51},"\u002F\u002F ⚠️ Even if the operation completes successfully, you MUST call cancel.\n",[45,585,586],{"class":47,"line":229},[45,587,588],{"class":51},"\u002F\u002F WithTimeout\u002FWithDeadline allocate a timer goroutine. cancel() stops it.\n",[45,590,591],{"class":47,"line":240},[45,592,593],{"class":51},"\u002F\u002F Without cancel, the timer lives until the deadline, leaking resources.\n",[28,595,597],{"id":596},"cancellation-propagation","Cancellation Propagation",[33,599,600,1158,1162],{"language":35},[37,601,603],{"className":39,"code":602,"language":35,"meta":41,"style":41},"\u002F\u002F ─── HTTP server: client disconnect cancels the context ───\nfunc handler(w http.ResponseWriter, r *http.Request) {\n    ctx := r.Context()  \u002F\u002F canceled when the client disconnects\n\n    \u002F\u002F Pass ctx to downstream calls — they're canceled when the client goes away:\n    user, err := fetchUser(ctx, userID)\n    if err != nil {\n        if errors.Is(err, context.Canceled) {\n            log.Println(\"client disconnected\")\n            return\n        }\n        http.Error(w, err.Error(), 500)\n        return\n    }\n\n    \u002F\u002F Long-running operation that respects cancellation:\n    if err := processBatch(ctx, user); err != nil {\n        http.Error(w, err.Error(), 500)\n        return\n    }\n}\n\n\u002F\u002F ─── Downstream function checks ctx.Done() ───\nfunc fetchUser(ctx context.Context, id int64) (*User, error) {\n    \u002F\u002F Quick check before work:\n    select {\n    case \u003C-ctx.Done():\n        return nil, ctx.Err()  \u002F\u002F already canceled\n    default:\n    }\n\n    req, _ := http.NewRequestWithContext(ctx, \"GET\",\n        fmt.Sprintf(\"https:\u002F\u002Fapi.example.com\u002Fusers\u002F%d\", id), nil)\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        return nil, fmt.Errorf(\"fetch user %d: %w\", id, err)\n    }\n    defer resp.Body.Close()\n\n    var u User\n    if err := json.NewDecoder(resp.Body).Decode(&u); err != nil {\n        return nil, fmt.Errorf(\"decode user %d: %w\", id, err)\n    }\n    return &u, nil\n}\n",[18,604,605,610,647,664,668,673,686,698,712,727,732,737,757,762,766,770,775,795,811,815,819,823,827,832,869,874,881,898,915,924,929,934,953,980,994,1007,1038,1043,1056,1061,1073,1108,1134,1139,1153],{"__ignoreMap":41},[45,606,607],{"class":47,"line":48},[45,608,609],{"class":51},"\u002F\u002F ─── HTTP server: client disconnect cancels the context ───\n",[45,611,612,614,617,619,622,625,627,630,632,635,638,640,642,645],{"class":47,"line":55},[45,613,148],{"class":147},[45,615,616],{"class":151}," handler",[45,618,330],{"class":155},[45,620,621],{"class":333},"w",[45,623,624],{"class":151}," http",[45,626,348],{"class":155},[45,628,629],{"class":151},"ResponseWriter",[45,631,265],{"class":155},[45,633,634],{"class":333},"r",[45,636,637],{"class":147}," *",[45,639,345],{"class":151},[45,641,348],{"class":155},[45,643,644],{"class":151},"Request",[45,646,359],{"class":155},[45,648,649,652,654,657,659,661],{"class":47,"line":61},[45,650,651],{"class":155},"    ctx ",[45,653,165],{"class":147},[45,655,656],{"class":155}," r.",[45,658,443],{"class":151},[45,660,192],{"class":155},[45,662,663],{"class":51},"\u002F\u002F canceled when the client disconnects\n",[45,665,666],{"class":47,"line":67},[45,667,141],{"emptyLinePlaceholder":140},[45,669,670],{"class":47,"line":73},[45,671,672],{"class":51},"    \u002F\u002F Pass ctx to downstream calls — they're canceled when the client goes away:\n",[45,674,675,678,680,683],{"class":47,"line":79},[45,676,677],{"class":155},"    user, err ",[45,679,165],{"class":147},[45,681,682],{"class":151}," fetchUser",[45,684,685],{"class":155},"(ctx, userID)\n",[45,687,688,690,692,694,696],{"class":47,"line":85},[45,689,530],{"class":147},[45,691,533],{"class":155},[45,693,536],{"class":147},[45,695,539],{"class":219},[45,697,542],{"class":155},[45,699,700,703,706,709],{"class":47,"line":91},[45,701,702],{"class":147},"        if",[45,704,705],{"class":155}," errors.",[45,707,708],{"class":151},"Is",[45,710,711],{"class":155},"(err, context.Canceled) {\n",[45,713,714,717,720,722,725],{"class":47,"line":97},[45,715,716],{"class":155},"            log.",[45,718,719],{"class":151},"Println",[45,721,330],{"class":155},[45,723,724],{"class":261},"\"client disconnected\"",[45,726,271],{"class":155},[45,728,729],{"class":47,"line":102},[45,730,731],{"class":147},"            return\n",[45,733,734],{"class":47,"line":108},[45,735,736],{"class":155},"        }\n",[45,738,739,742,745,748,750,752,755],{"class":47,"line":114},[45,740,741],{"class":155},"        http.",[45,743,744],{"class":151},"Error",[45,746,747],{"class":155},"(w, err.",[45,749,744],{"class":151},[45,751,377],{"class":155},[45,753,754],{"class":219},"500",[45,756,271],{"class":155},[45,758,759],{"class":47,"line":119},[45,760,761],{"class":147},"        return\n",[45,763,764],{"class":47,"line":125},[45,765,557],{"class":155},[45,767,768],{"class":47,"line":131},[45,769,141],{"emptyLinePlaceholder":140},[45,771,772],{"class":47,"line":137},[45,773,774],{"class":51},"    \u002F\u002F Long-running operation that respects cancellation:\n",[45,776,777,779,781,783,786,789,791,793],{"class":47,"line":144},[45,778,530],{"class":147},[45,780,533],{"class":155},[45,782,165],{"class":147},[45,784,785],{"class":151}," processBatch",[45,787,788],{"class":155},"(ctx, user); err ",[45,790,536],{"class":147},[45,792,539],{"class":219},[45,794,542],{"class":155},[45,796,797,799,801,803,805,807,809],{"class":47,"line":159},[45,798,741],{"class":155},[45,800,744],{"class":151},[45,802,747],{"class":155},[45,804,744],{"class":151},[45,806,377],{"class":155},[45,808,754],{"class":219},[45,810,271],{"class":155},[45,812,813],{"class":47,"line":183},[45,814,761],{"class":147},[45,816,817],{"class":47,"line":198},[45,818,557],{"class":155},[45,820,821],{"class":47,"line":203},[45,822,301],{"class":155},[45,824,825],{"class":47,"line":229},[45,826,141],{"emptyLinePlaceholder":140},[45,828,829],{"class":47,"line":240},[45,830,831],{"class":51},"\u002F\u002F ─── Downstream function checks ctx.Done() ───\n",[45,833,834,836,838,840,842,844,846,848,850,853,856,858,860,863,865,867],{"class":47,"line":245},[45,835,148],{"class":147},[45,837,682],{"class":151},[45,839,330],{"class":155},[45,841,435],{"class":333},[45,843,438],{"class":151},[45,845,348],{"class":155},[45,847,443],{"class":151},[45,849,265],{"class":155},[45,851,852],{"class":333},"id",[45,854,855],{"class":147}," int64",[45,857,340],{"class":155},[45,859,223],{"class":147},[45,861,862],{"class":151},"User",[45,864,265],{"class":155},[45,866,356],{"class":147},[45,868,359],{"class":155},[45,870,871],{"class":47,"line":274},[45,872,873],{"class":51},"    \u002F\u002F Quick check before work:\n",[45,875,876,879],{"class":47,"line":280},[45,877,878],{"class":147},"    select",[45,880,542],{"class":155},[45,882,883,886,889,892,895],{"class":47,"line":286},[45,884,885],{"class":147},"    case",[45,887,888],{"class":147}," \u003C-",[45,890,891],{"class":155},"ctx.",[45,893,894],{"class":151},"Done",[45,896,897],{"class":155},"():\n",[45,899,900,902,904,907,910,912],{"class":47,"line":298},[45,901,547],{"class":147},[45,903,539],{"class":219},[45,905,906],{"class":155},", ctx.",[45,908,909],{"class":151},"Err",[45,911,192],{"class":155},[45,913,914],{"class":51},"\u002F\u002F already canceled\n",[45,916,918,921],{"class":47,"line":917},29,[45,919,920],{"class":147},"    default",[45,922,923],{"class":155},":\n",[45,925,927],{"class":47,"line":926},30,[45,928,557],{"class":155},[45,930,932],{"class":47,"line":931},31,[45,933,141],{"emptyLinePlaceholder":140},[45,935,937,940,942,944,946,948,950],{"class":47,"line":936},32,[45,938,939],{"class":155},"    req, _ ",[45,941,165],{"class":147},[45,943,401],{"class":155},[45,945,512],{"class":151},[45,947,479],{"class":155},[45,949,517],{"class":261},[45,951,952],{"class":155},",\n",[45,954,956,959,962,964,967,970,973,976,978],{"class":47,"line":955},33,[45,957,958],{"class":155},"        fmt.",[45,960,961],{"class":151},"Sprintf",[45,963,330],{"class":155},[45,965,966],{"class":261},"\"https:\u002F\u002Fapi.example.com\u002Fusers\u002F",[45,968,969],{"class":219},"%d",[45,971,972],{"class":261},"\"",[45,974,975],{"class":155},", id), ",[45,977,523],{"class":219},[45,979,271],{"class":155},[45,981,983,986,988,990,992],{"class":47,"line":982},34,[45,984,985],{"class":155},"    resp, err ",[45,987,165],{"class":147},[45,989,564],{"class":155},[45,991,567],{"class":151},[45,993,570],{"class":155},[45,995,997,999,1001,1003,1005],{"class":47,"line":996},35,[45,998,530],{"class":147},[45,1000,533],{"class":155},[45,1002,536],{"class":147},[45,1004,539],{"class":219},[45,1006,542],{"class":155},[45,1008,1010,1012,1014,1017,1020,1022,1025,1027,1030,1033,1035],{"class":47,"line":1009},36,[45,1011,547],{"class":147},[45,1013,539],{"class":219},[45,1015,1016],{"class":155},", fmt.",[45,1018,1019],{"class":151},"Errorf",[45,1021,330],{"class":155},[45,1023,1024],{"class":261},"\"fetch user ",[45,1026,969],{"class":219},[45,1028,1029],{"class":261},": ",[45,1031,1032],{"class":219},"%w",[45,1034,972],{"class":261},[45,1036,1037],{"class":155},", id, err)\n",[45,1039,1041],{"class":47,"line":1040},37,[45,1042,557],{"class":155},[45,1044,1046,1048,1051,1054],{"class":47,"line":1045},38,[45,1047,186],{"class":147},[45,1049,1050],{"class":155}," resp.Body.",[45,1052,1053],{"class":151},"Close",[45,1055,237],{"class":155},[45,1057,1059],{"class":47,"line":1058},39,[45,1060,141],{"emptyLinePlaceholder":140},[45,1062,1064,1067,1070],{"class":47,"line":1063},40,[45,1065,1066],{"class":147},"    var",[45,1068,1069],{"class":155}," u ",[45,1071,1072],{"class":151},"User\n",[45,1074,1076,1078,1080,1082,1085,1088,1091,1094,1096,1099,1102,1104,1106],{"class":47,"line":1075},41,[45,1077,530],{"class":147},[45,1079,533],{"class":155},[45,1081,165],{"class":147},[45,1083,1084],{"class":155}," json.",[45,1086,1087],{"class":151},"NewDecoder",[45,1089,1090],{"class":155},"(resp.Body).",[45,1092,1093],{"class":151},"Decode",[45,1095,330],{"class":155},[45,1097,1098],{"class":147},"&",[45,1100,1101],{"class":155},"u); err ",[45,1103,536],{"class":147},[45,1105,539],{"class":219},[45,1107,542],{"class":155},[45,1109,1111,1113,1115,1117,1119,1121,1124,1126,1128,1130,1132],{"class":47,"line":1110},42,[45,1112,547],{"class":147},[45,1114,539],{"class":219},[45,1116,1016],{"class":155},[45,1118,1019],{"class":151},[45,1120,330],{"class":155},[45,1122,1123],{"class":261},"\"decode user ",[45,1125,969],{"class":219},[45,1127,1029],{"class":261},[45,1129,1032],{"class":219},[45,1131,972],{"class":261},[45,1133,1037],{"class":155},[45,1135,1137],{"class":47,"line":1136},43,[45,1138,557],{"class":155},[45,1140,1142,1144,1147,1150],{"class":47,"line":1141},44,[45,1143,398],{"class":147},[45,1145,1146],{"class":147}," &",[45,1148,1149],{"class":155},"u, ",[45,1151,1152],{"class":219},"nil\n",[45,1154,1156],{"class":47,"line":1155},45,[45,1157,301],{"class":155},[28,1159,1161],{"id":1160},"worker-goroutine-with-cancellation","Worker Goroutine with Cancellation",[33,1163,1164,1573,1577],{"language":35},[37,1165,1167],{"className":39,"code":1166,"language":35,"meta":41,"style":41},"func worker(ctx context.Context, input \u003C-chan int, output chan\u003C- int) error {\n    for {\n        select {\n        case v, ok := \u003C-input:\n            if !ok {\n                return nil  \u002F\u002F input closed — clean exit\n            }\n            \u002F\u002F Pass ctx to process so it can be canceled mid-computation:\n            result, err := process(ctx, v)\n            if err != nil {\n                return err\n            }\n            select {\n            case output \u003C- result:\n            case \u003C-ctx.Done():\n                return ctx.Err()  \u002F\u002F canceled while sending\n            }\n        case \u003C-ctx.Done():\n            return ctx.Err()  \u002F\u002F canceled — exit cleanly\n        }\n    }\n}\n\n\u002F\u002F ─── CPU-bound loop with periodic cancellation checks ───\nfunc computeIntensive(ctx context.Context, data []int) (int, error) {\n    total := 0\n    for i, v := range data {\n        \u002F\u002F Check for cancellation every 1000 iterations (cheap):\n        if i%1000 == 0 {\n            select {\n            case \u003C-ctx.Done():\n                return 0, ctx.Err()\n            default:\n            }\n        }\n        total += expensiveOp(v)\n    }\n    return total, nil\n}\n",[18,1168,1169,1214,1221,1228,1243,1254,1264,1269,1274,1287,1299,1306,1310,1317,1331,1343,1357,1361,1373,1387,1391,1395,1399,1403,1408,1446,1456,1471,1476,1497,1503,1515,1527,1534,1538,1542,1556,1560,1569],{"__ignoreMap":41},[45,1170,1171,1173,1176,1178,1180,1182,1184,1186,1188,1191,1194,1197,1199,1202,1205,1207,1210,1212],{"class":47,"line":48},[45,1172,148],{"class":147},[45,1174,1175],{"class":151}," worker",[45,1177,330],{"class":155},[45,1179,435],{"class":333},[45,1181,438],{"class":151},[45,1183,348],{"class":155},[45,1185,443],{"class":151},[45,1187,265],{"class":155},[45,1189,1190],{"class":333},"input",[45,1192,1193],{"class":147}," \u003C-chan",[45,1195,1196],{"class":147}," int",[45,1198,265],{"class":155},[45,1200,1201],{"class":333},"output",[45,1203,1204],{"class":147}," chan\u003C-",[45,1206,1196],{"class":147},[45,1208,1209],{"class":155},") ",[45,1211,356],{"class":147},[45,1213,542],{"class":155},[45,1215,1216,1219],{"class":47,"line":55},[45,1217,1218],{"class":147},"    for",[45,1220,542],{"class":155},[45,1222,1223,1226],{"class":47,"line":61},[45,1224,1225],{"class":147},"        select",[45,1227,542],{"class":155},[45,1229,1230,1233,1236,1238,1240],{"class":47,"line":67},[45,1231,1232],{"class":147},"        case",[45,1234,1235],{"class":155}," v, ok ",[45,1237,165],{"class":147},[45,1239,888],{"class":147},[45,1241,1242],{"class":155},"input:\n",[45,1244,1245,1248,1251],{"class":47,"line":73},[45,1246,1247],{"class":147},"            if",[45,1249,1250],{"class":147}," !",[45,1252,1253],{"class":155},"ok {\n",[45,1255,1256,1259,1261],{"class":47,"line":79},[45,1257,1258],{"class":147},"                return",[45,1260,539],{"class":219},[45,1262,1263],{"class":51},"  \u002F\u002F input closed — clean exit\n",[45,1265,1266],{"class":47,"line":85},[45,1267,1268],{"class":155},"            }\n",[45,1270,1271],{"class":47,"line":91},[45,1272,1273],{"class":51},"            \u002F\u002F Pass ctx to process so it can be canceled mid-computation:\n",[45,1275,1276,1279,1281,1284],{"class":47,"line":97},[45,1277,1278],{"class":155},"            result, err ",[45,1280,165],{"class":147},[45,1282,1283],{"class":151}," process",[45,1285,1286],{"class":155},"(ctx, v)\n",[45,1288,1289,1291,1293,1295,1297],{"class":47,"line":102},[45,1290,1247],{"class":147},[45,1292,533],{"class":155},[45,1294,536],{"class":147},[45,1296,539],{"class":219},[45,1298,542],{"class":155},[45,1300,1301,1303],{"class":47,"line":108},[45,1302,1258],{"class":147},[45,1304,1305],{"class":155}," err\n",[45,1307,1308],{"class":47,"line":114},[45,1309,1268],{"class":155},[45,1311,1312,1315],{"class":47,"line":119},[45,1313,1314],{"class":147},"            select",[45,1316,542],{"class":155},[45,1318,1319,1322,1325,1328],{"class":47,"line":125},[45,1320,1321],{"class":147},"            case",[45,1323,1324],{"class":155}," output ",[45,1326,1327],{"class":147},"\u003C-",[45,1329,1330],{"class":155}," result:\n",[45,1332,1333,1335,1337,1339,1341],{"class":47,"line":131},[45,1334,1321],{"class":147},[45,1336,888],{"class":147},[45,1338,891],{"class":155},[45,1340,894],{"class":151},[45,1342,897],{"class":155},[45,1344,1345,1347,1350,1352,1354],{"class":47,"line":137},[45,1346,1258],{"class":147},[45,1348,1349],{"class":155}," ctx.",[45,1351,909],{"class":151},[45,1353,192],{"class":155},[45,1355,1356],{"class":51},"\u002F\u002F canceled while sending\n",[45,1358,1359],{"class":47,"line":144},[45,1360,1268],{"class":155},[45,1362,1363,1365,1367,1369,1371],{"class":47,"line":159},[45,1364,1232],{"class":147},[45,1366,888],{"class":147},[45,1368,891],{"class":155},[45,1370,894],{"class":151},[45,1372,897],{"class":155},[45,1374,1375,1378,1380,1382,1384],{"class":47,"line":183},[45,1376,1377],{"class":147},"            return",[45,1379,1349],{"class":155},[45,1381,909],{"class":151},[45,1383,192],{"class":155},[45,1385,1386],{"class":51},"\u002F\u002F canceled — exit cleanly\n",[45,1388,1389],{"class":47,"line":198},[45,1390,736],{"class":155},[45,1392,1393],{"class":47,"line":203},[45,1394,557],{"class":155},[45,1396,1397],{"class":47,"line":229},[45,1398,301],{"class":155},[45,1400,1401],{"class":47,"line":240},[45,1402,141],{"emptyLinePlaceholder":140},[45,1404,1405],{"class":47,"line":245},[45,1406,1407],{"class":51},"\u002F\u002F ─── CPU-bound loop with periodic cancellation checks ───\n",[45,1409,1410,1412,1415,1417,1419,1421,1423,1425,1427,1430,1433,1436,1438,1440,1442,1444],{"class":47,"line":274},[45,1411,148],{"class":147},[45,1413,1414],{"class":151}," computeIntensive",[45,1416,330],{"class":155},[45,1418,435],{"class":333},[45,1420,438],{"class":151},[45,1422,348],{"class":155},[45,1424,443],{"class":151},[45,1426,265],{"class":155},[45,1428,1429],{"class":333},"data",[45,1431,1432],{"class":155}," []",[45,1434,1435],{"class":147},"int",[45,1437,340],{"class":155},[45,1439,1435],{"class":147},[45,1441,265],{"class":155},[45,1443,356],{"class":147},[45,1445,359],{"class":155},[45,1447,1448,1451,1453],{"class":47,"line":280},[45,1449,1450],{"class":155},"    total ",[45,1452,165],{"class":147},[45,1454,1455],{"class":219}," 0\n",[45,1457,1458,1460,1463,1465,1468],{"class":47,"line":286},[45,1459,1218],{"class":147},[45,1461,1462],{"class":155}," i, v ",[45,1464,165],{"class":147},[45,1466,1467],{"class":147}," range",[45,1469,1470],{"class":155}," data {\n",[45,1472,1473],{"class":47,"line":298},[45,1474,1475],{"class":51},"        \u002F\u002F Check for cancellation every 1000 iterations (cheap):\n",[45,1477,1478,1480,1483,1486,1489,1492,1495],{"class":47,"line":917},[45,1479,702],{"class":147},[45,1481,1482],{"class":155}," i",[45,1484,1485],{"class":147},"%",[45,1487,1488],{"class":219},"1000",[45,1490,1491],{"class":147}," ==",[45,1493,1494],{"class":219}," 0",[45,1496,542],{"class":155},[45,1498,1499,1501],{"class":47,"line":926},[45,1500,1314],{"class":147},[45,1502,542],{"class":155},[45,1504,1505,1507,1509,1511,1513],{"class":47,"line":931},[45,1506,1321],{"class":147},[45,1508,888],{"class":147},[45,1510,891],{"class":155},[45,1512,894],{"class":151},[45,1514,897],{"class":155},[45,1516,1517,1519,1521,1523,1525],{"class":47,"line":936},[45,1518,1258],{"class":147},[45,1520,1494],{"class":219},[45,1522,906],{"class":155},[45,1524,909],{"class":151},[45,1526,237],{"class":155},[45,1528,1529,1532],{"class":47,"line":955},[45,1530,1531],{"class":147},"            default",[45,1533,923],{"class":155},[45,1535,1536],{"class":47,"line":982},[45,1537,1268],{"class":155},[45,1539,1540],{"class":47,"line":996},[45,1541,736],{"class":155},[45,1543,1544,1547,1550,1553],{"class":47,"line":1009},[45,1545,1546],{"class":155},"        total ",[45,1548,1549],{"class":147},"+=",[45,1551,1552],{"class":151}," expensiveOp",[45,1554,1555],{"class":155},"(v)\n",[45,1557,1558],{"class":47,"line":1040},[45,1559,557],{"class":155},[45,1561,1562,1564,1567],{"class":47,"line":1045},[45,1563,398],{"class":147},[45,1565,1566],{"class":155}," total, ",[45,1568,1152],{"class":219},[45,1570,1571],{"class":47,"line":1058},[45,1572,301],{"class":155},[28,1574,1576],{"id":1575},"request-scoped-values-use-sparingly","Request-Scoped Values — Use Sparingly",[33,1578,1579,1822,1826],{"language":35},[37,1580,1582],{"className":39,"code":1581,"language":35,"meta":41,"style":41},"\u002F\u002F WithValue carries request-scoped data (request ID, trace ID, user ID).\n\u002F\u002F ⚠️ Use ONLY for cross-cutting concerns that flow through every function\n\u002F\u002F without explicit threading. Prefer explicit parameters for most data.\n\n\u002F\u002F ✅ Type-safe keys (custom type prevents collisions):\ntype ctxKey int  \u002F\u002F unexported type — other packages can't collide\n\nconst (\n    keyRequestID ctxKey = iota\n    keyUserID\n    keyTraceID\n)\n\nfunc withRequestID(ctx context.Context, id string) context.Context {\n    return context.WithValue(ctx, keyRequestID, id)\n}\n\nfunc requestIDFrom(ctx context.Context) string {\n    if v, ok := ctx.Value(keyRequestID).(string); ok {\n        return v\n    }\n    return \"\"  \u002F\u002F no request ID in context\n}\n\n\u002F\u002F ❌ ANTI-PATTERN: using string keys (collision risk)\n\u002F\u002F ctx = context.WithValue(ctx, \"userID\", 42)\n\u002F\u002F Another package might use \"userID\" for something else → collision\n\n\u002F\u002F ❌ ANTI-PATTERN: using WithValue for business data (not cross-cutting)\n\u002F\u002F ctx = context.WithValue(ctx, \"user\", user)  \u002F\u002F pass user as a parameter!\n",[18,1583,1584,1589,1594,1599,1603,1608,1621,1625,1633,1646,1651,1656,1660,1664,1697,1708,1712,1716,1740,1761,1768,1772,1782,1786,1790,1795,1800,1805,1809,1814],{"__ignoreMap":41},[45,1585,1586],{"class":47,"line":48},[45,1587,1588],{"class":51},"\u002F\u002F WithValue carries request-scoped data (request ID, trace ID, user ID).\n",[45,1590,1591],{"class":47,"line":55},[45,1592,1593],{"class":51},"\u002F\u002F ⚠️ Use ONLY for cross-cutting concerns that flow through every function\n",[45,1595,1596],{"class":47,"line":61},[45,1597,1598],{"class":51},"\u002F\u002F without explicit threading. Prefer explicit parameters for most data.\n",[45,1600,1601],{"class":47,"line":67},[45,1602,141],{"emptyLinePlaceholder":140},[45,1604,1605],{"class":47,"line":73},[45,1606,1607],{"class":51},"\u002F\u002F ✅ Type-safe keys (custom type prevents collisions):\n",[45,1609,1610,1613,1616,1618],{"class":47,"line":79},[45,1611,1612],{"class":147},"type",[45,1614,1615],{"class":151}," ctxKey",[45,1617,1196],{"class":147},[45,1619,1620],{"class":51},"  \u002F\u002F unexported type — other packages can't collide\n",[45,1622,1623],{"class":47,"line":85},[45,1624,141],{"emptyLinePlaceholder":140},[45,1626,1627,1630],{"class":47,"line":91},[45,1628,1629],{"class":147},"const",[45,1631,1632],{"class":155}," (\n",[45,1634,1635,1638,1640,1643],{"class":47,"line":97},[45,1636,1637],{"class":219},"    keyRequestID",[45,1639,1615],{"class":151},[45,1641,1642],{"class":147}," =",[45,1644,1645],{"class":219}," iota\n",[45,1647,1648],{"class":47,"line":102},[45,1649,1650],{"class":219},"    keyUserID\n",[45,1652,1653],{"class":47,"line":108},[45,1654,1655],{"class":219},"    keyTraceID\n",[45,1657,1658],{"class":47,"line":114},[45,1659,271],{"class":155},[45,1661,1662],{"class":47,"line":119},[45,1663,141],{"emptyLinePlaceholder":140},[45,1665,1666,1668,1671,1673,1675,1677,1679,1681,1683,1685,1687,1689,1691,1693,1695],{"class":47,"line":125},[45,1667,148],{"class":147},[45,1669,1670],{"class":151}," withRequestID",[45,1672,330],{"class":155},[45,1674,435],{"class":333},[45,1676,438],{"class":151},[45,1678,348],{"class":155},[45,1680,443],{"class":151},[45,1682,265],{"class":155},[45,1684,852],{"class":333},[45,1686,337],{"class":147},[45,1688,1209],{"class":155},[45,1690,20],{"class":151},[45,1692,348],{"class":155},[45,1694,443],{"class":151},[45,1696,542],{"class":155},[45,1698,1699,1701,1703,1705],{"class":47,"line":131},[45,1700,398],{"class":147},[45,1702,168],{"class":155},[45,1704,255],{"class":151},[45,1706,1707],{"class":155},"(ctx, keyRequestID, id)\n",[45,1709,1710],{"class":47,"line":137},[45,1711,301],{"class":155},[45,1713,1714],{"class":47,"line":144},[45,1715,141],{"emptyLinePlaceholder":140},[45,1717,1718,1720,1723,1725,1727,1729,1731,1733,1735,1738],{"class":47,"line":159},[45,1719,148],{"class":147},[45,1721,1722],{"class":151}," requestIDFrom",[45,1724,330],{"class":155},[45,1726,435],{"class":333},[45,1728,438],{"class":151},[45,1730,348],{"class":155},[45,1732,443],{"class":151},[45,1734,1209],{"class":155},[45,1736,1737],{"class":147},"string",[45,1739,542],{"class":155},[45,1741,1742,1744,1746,1748,1750,1753,1756,1758],{"class":47,"line":183},[45,1743,530],{"class":147},[45,1745,1235],{"class":155},[45,1747,165],{"class":147},[45,1749,1349],{"class":155},[45,1751,1752],{"class":151},"Value",[45,1754,1755],{"class":155},"(keyRequestID).(",[45,1757,1737],{"class":147},[45,1759,1760],{"class":155},"); ok {\n",[45,1762,1763,1765],{"class":47,"line":198},[45,1764,547],{"class":147},[45,1766,1767],{"class":155}," v\n",[45,1769,1770],{"class":47,"line":203},[45,1771,557],{"class":155},[45,1773,1774,1776,1779],{"class":47,"line":229},[45,1775,398],{"class":147},[45,1777,1778],{"class":261}," \"\"",[45,1780,1781],{"class":51},"  \u002F\u002F no request ID in context\n",[45,1783,1784],{"class":47,"line":240},[45,1785,301],{"class":155},[45,1787,1788],{"class":47,"line":245},[45,1789,141],{"emptyLinePlaceholder":140},[45,1791,1792],{"class":47,"line":274},[45,1793,1794],{"class":51},"\u002F\u002F ❌ ANTI-PATTERN: using string keys (collision risk)\n",[45,1796,1797],{"class":47,"line":280},[45,1798,1799],{"class":51},"\u002F\u002F ctx = context.WithValue(ctx, \"userID\", 42)\n",[45,1801,1802],{"class":47,"line":286},[45,1803,1804],{"class":51},"\u002F\u002F Another package might use \"userID\" for something else → collision\n",[45,1806,1807],{"class":47,"line":298},[45,1808,141],{"emptyLinePlaceholder":140},[45,1810,1811],{"class":47,"line":917},[45,1812,1813],{"class":51},"\u002F\u002F ❌ ANTI-PATTERN: using WithValue for business data (not cross-cutting)\n",[45,1815,1816,1819],{"class":47,"line":926},[45,1817,1818],{"class":51},"\u002F\u002F ctx = context.WithValue(ctx, \"user\", user)",[45,1820,1821],{"class":51},"  \u002F\u002F pass user as a parameter!\n",[28,1823,1825],{"id":1824},"production-pattern-request-id-middleware","Production Pattern — Request ID Middleware",[33,1827,1828,2161,2168],{"language":35},[37,1829,1831],{"className":39,"code":1830,"language":35,"meta":41,"style":41},"type ctxKey int\nconst keyRequestID ctxKey = 0\n\nfunc RequestIDMiddleware(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        \u002F\u002F Generate or extract request ID:\n        reqID := r.Header.Get(\"X-Request-ID\")\n        if reqID == \"\" {\n            reqID = uuid.NewString()\n        }\n\n        \u002F\u002F Add to context for downstream handlers:\n        ctx := context.WithValue(r.Context(), keyRequestID, reqID)\n\n        \u002F\u002F Add to response header for client correlation:\n        w.Header().Set(\"X-Request-ID\", reqID)\n\n        next.ServeHTTP(w, r.WithContext(ctx))\n    })\n}\n\n\u002F\u002F Downstream handlers extract the request ID for logging:\nfunc myHandler(w http.ResponseWriter, r *http.Request) {\n    reqID := r.Context().Value(keyRequestID).(string)\n    log.Printf(\"[%s] handling request\", reqID)\n    \u002F\u002F ...\n}\n",[18,1832,1833,1842,1855,1859,1888,1925,1930,1949,1963,1978,1982,1986,1991,2010,2014,2019,2040,2044,2061,2066,2070,2074,2079,2110,2131,2152,2157],{"__ignoreMap":41},[45,1834,1835,1837,1839],{"class":47,"line":48},[45,1836,1612],{"class":147},[45,1838,1615],{"class":151},[45,1840,1841],{"class":147}," int\n",[45,1843,1844,1846,1849,1851,1853],{"class":47,"line":55},[45,1845,1629],{"class":147},[45,1847,1848],{"class":219}," keyRequestID",[45,1850,1615],{"class":151},[45,1852,1642],{"class":147},[45,1854,1455],{"class":219},[45,1856,1857],{"class":47,"line":61},[45,1858,141],{"emptyLinePlaceholder":140},[45,1860,1861,1863,1866,1868,1871,1873,1875,1878,1880,1882,1884,1886],{"class":47,"line":67},[45,1862,148],{"class":147},[45,1864,1865],{"class":151}," RequestIDMiddleware",[45,1867,330],{"class":155},[45,1869,1870],{"class":333},"next",[45,1872,624],{"class":151},[45,1874,348],{"class":155},[45,1876,1877],{"class":151},"Handler",[45,1879,1209],{"class":155},[45,1881,345],{"class":151},[45,1883,348],{"class":155},[45,1885,1877],{"class":151},[45,1887,542],{"class":155},[45,1889,1890,1892,1894,1897,1899,1901,1903,1905,1907,1909,1911,1913,1915,1917,1919,1921,1923],{"class":47,"line":73},[45,1891,398],{"class":147},[45,1893,401],{"class":155},[45,1895,1896],{"class":151},"HandlerFunc",[45,1898,330],{"class":155},[45,1900,148],{"class":147},[45,1902,330],{"class":155},[45,1904,621],{"class":333},[45,1906,624],{"class":151},[45,1908,348],{"class":155},[45,1910,629],{"class":151},[45,1912,265],{"class":155},[45,1914,634],{"class":333},[45,1916,637],{"class":147},[45,1918,345],{"class":151},[45,1920,348],{"class":155},[45,1922,644],{"class":151},[45,1924,359],{"class":155},[45,1926,1927],{"class":47,"line":79},[45,1928,1929],{"class":51},"        \u002F\u002F Generate or extract request ID:\n",[45,1931,1932,1935,1937,1940,1942,1944,1947],{"class":47,"line":85},[45,1933,1934],{"class":155},"        reqID ",[45,1936,165],{"class":147},[45,1938,1939],{"class":155}," r.Header.",[45,1941,404],{"class":151},[45,1943,330],{"class":155},[45,1945,1946],{"class":261},"\"X-Request-ID\"",[45,1948,271],{"class":155},[45,1950,1951,1953,1956,1959,1961],{"class":47,"line":91},[45,1952,702],{"class":147},[45,1954,1955],{"class":155}," reqID ",[45,1957,1958],{"class":147},"==",[45,1960,1778],{"class":261},[45,1962,542],{"class":155},[45,1964,1965,1968,1970,1973,1976],{"class":47,"line":97},[45,1966,1967],{"class":155},"            reqID ",[45,1969,292],{"class":147},[45,1971,1972],{"class":155}," uuid.",[45,1974,1975],{"class":151},"NewString",[45,1977,237],{"class":155},[45,1979,1980],{"class":47,"line":102},[45,1981,736],{"class":155},[45,1983,1984],{"class":47,"line":108},[45,1985,141],{"emptyLinePlaceholder":140},[45,1987,1988],{"class":47,"line":114},[45,1989,1990],{"class":51},"        \u002F\u002F Add to context for downstream handlers:\n",[45,1992,1993,1996,1998,2000,2002,2005,2007],{"class":47,"line":119},[45,1994,1995],{"class":155},"        ctx ",[45,1997,165],{"class":147},[45,1999,168],{"class":155},[45,2001,255],{"class":151},[45,2003,2004],{"class":155},"(r.",[45,2006,443],{"class":151},[45,2008,2009],{"class":155},"(), keyRequestID, reqID)\n",[45,2011,2012],{"class":47,"line":125},[45,2013,141],{"emptyLinePlaceholder":140},[45,2015,2016],{"class":47,"line":131},[45,2017,2018],{"class":51},"        \u002F\u002F Add to response header for client correlation:\n",[45,2020,2021,2024,2027,2030,2033,2035,2037],{"class":47,"line":137},[45,2022,2023],{"class":155},"        w.",[45,2025,2026],{"class":151},"Header",[45,2028,2029],{"class":155},"().",[45,2031,2032],{"class":151},"Set",[45,2034,330],{"class":155},[45,2036,1946],{"class":261},[45,2038,2039],{"class":155},", reqID)\n",[45,2041,2042],{"class":47,"line":144},[45,2043,141],{"emptyLinePlaceholder":140},[45,2045,2046,2049,2052,2055,2058],{"class":47,"line":159},[45,2047,2048],{"class":155},"        next.",[45,2050,2051],{"class":151},"ServeHTTP",[45,2053,2054],{"class":155},"(w, r.",[45,2056,2057],{"class":151},"WithContext",[45,2059,2060],{"class":155},"(ctx))\n",[45,2062,2063],{"class":47,"line":183},[45,2064,2065],{"class":155},"    })\n",[45,2067,2068],{"class":47,"line":198},[45,2069,301],{"class":155},[45,2071,2072],{"class":47,"line":203},[45,2073,141],{"emptyLinePlaceholder":140},[45,2075,2076],{"class":47,"line":229},[45,2077,2078],{"class":51},"\u002F\u002F Downstream handlers extract the request ID for logging:\n",[45,2080,2081,2083,2086,2088,2090,2092,2094,2096,2098,2100,2102,2104,2106,2108],{"class":47,"line":240},[45,2082,148],{"class":147},[45,2084,2085],{"class":151}," myHandler",[45,2087,330],{"class":155},[45,2089,621],{"class":333},[45,2091,624],{"class":151},[45,2093,348],{"class":155},[45,2095,629],{"class":151},[45,2097,265],{"class":155},[45,2099,634],{"class":333},[45,2101,637],{"class":147},[45,2103,345],{"class":151},[45,2105,348],{"class":155},[45,2107,644],{"class":151},[45,2109,359],{"class":155},[45,2111,2112,2115,2117,2119,2121,2123,2125,2127,2129],{"class":47,"line":245},[45,2113,2114],{"class":155},"    reqID ",[45,2116,165],{"class":147},[45,2118,656],{"class":155},[45,2120,443],{"class":151},[45,2122,2029],{"class":155},[45,2124,1752],{"class":151},[45,2126,1755],{"class":155},[45,2128,1737],{"class":147},[45,2130,271],{"class":155},[45,2132,2133,2136,2139,2141,2144,2147,2150],{"class":47,"line":274},[45,2134,2135],{"class":155},"    log.",[45,2137,2138],{"class":151},"Printf",[45,2140,330],{"class":155},[45,2142,2143],{"class":261},"\"[",[45,2145,2146],{"class":219},"%s",[45,2148,2149],{"class":261},"] handling request\"",[45,2151,2039],{"class":155},[45,2153,2154],{"class":47,"line":280},[45,2155,2156],{"class":51},"    \u002F\u002F ...\n",[45,2158,2159],{"class":47,"line":286},[45,2160,301],{"class":155},[28,2162,2164,2167],{"id":2163},"errgroupgroup-bounded-concurrent-error-handling",[18,2165,2166],{},"errgroup.Group"," — Bounded Concurrent Error Handling",[33,2169,2170,2470,2474,2564,2568,2694,2698],{"language":35},[37,2171,2173],{"className":39,"code":2172,"language":35,"meta":41,"style":41},"\u002F\u002F import \"golang.org\u002Fx\u002Fsync\u002Ferrgroup\"\n\u002F\u002F errgroup.Group runs goroutines and returns the FIRST error.\n\u002F\u002F It also provides bounded concurrency via SetLimit.\n\nfunc fetchAll(ctx context.Context, urls []string) ([][]byte, error) {\n    g, ctx := errgroup.WithContext(ctx)  \u002F\u002F ctx canceled if any goroutine errors\n\n    results := make([][]byte, len(urls))\n    g.SetLimit(10)  \u002F\u002F at most 10 concurrent goroutines\n\n    for i, url := range urls {\n        i, url := i, url  \u002F\u002F capture (pre-1.22; 1.22+ doesn't need this)\n        g.Go(func() error {\n            data, err := fetch(ctx, url)\n            if err != nil {\n                return err  \u002F\u002F cancels ctx and stops other goroutines\n            }\n            results[i] = data  \u002F\u002F safe — each goroutine writes a distinct index\n            return nil\n        })\n    }\n\n    if err := g.Wait(); err != nil {\n        return nil, err  \u002F\u002F first error from any goroutine\n    }\n    return results, nil\n}\n",[18,2174,2175,2180,2185,2190,2194,2232,2250,2254,2277,2296,2300,2314,2327,2346,2359,2371,2381,2385,2398,2405,2410,2414,2418,2441,2453,2457,2466],{"__ignoreMap":41},[45,2176,2177],{"class":47,"line":48},[45,2178,2179],{"class":51},"\u002F\u002F import \"golang.org\u002Fx\u002Fsync\u002Ferrgroup\"\n",[45,2181,2182],{"class":47,"line":55},[45,2183,2184],{"class":51},"\u002F\u002F errgroup.Group runs goroutines and returns the FIRST error.\n",[45,2186,2187],{"class":47,"line":61},[45,2188,2189],{"class":51},"\u002F\u002F It also provides bounded concurrency via SetLimit.\n",[45,2191,2192],{"class":47,"line":67},[45,2193,141],{"emptyLinePlaceholder":140},[45,2195,2196,2198,2201,2203,2205,2207,2209,2211,2213,2216,2218,2220,2223,2226,2228,2230],{"class":47,"line":73},[45,2197,148],{"class":147},[45,2199,2200],{"class":151}," fetchAll",[45,2202,330],{"class":155},[45,2204,435],{"class":333},[45,2206,438],{"class":151},[45,2208,348],{"class":155},[45,2210,443],{"class":151},[45,2212,265],{"class":155},[45,2214,2215],{"class":333},"urls",[45,2217,1432],{"class":155},[45,2219,1737],{"class":147},[45,2221,2222],{"class":155},") ([][]",[45,2224,2225],{"class":147},"byte",[45,2227,265],{"class":155},[45,2229,356],{"class":147},[45,2231,359],{"class":155},[45,2233,2234,2237,2239,2242,2244,2247],{"class":47,"line":79},[45,2235,2236],{"class":155},"    g, ctx ",[45,2238,165],{"class":147},[45,2240,2241],{"class":155}," errgroup.",[45,2243,2057],{"class":151},[45,2245,2246],{"class":155},"(ctx)  ",[45,2248,2249],{"class":51},"\u002F\u002F ctx canceled if any goroutine errors\n",[45,2251,2252],{"class":47,"line":85},[45,2253,141],{"emptyLinePlaceholder":140},[45,2255,2256,2259,2261,2264,2267,2269,2271,2274],{"class":47,"line":91},[45,2257,2258],{"class":155},"    results ",[45,2260,165],{"class":147},[45,2262,2263],{"class":151}," make",[45,2265,2266],{"class":155},"([][]",[45,2268,2225],{"class":147},[45,2270,265],{"class":155},[45,2272,2273],{"class":151},"len",[45,2275,2276],{"class":155},"(urls))\n",[45,2278,2279,2282,2285,2287,2290,2293],{"class":47,"line":97},[45,2280,2281],{"class":155},"    g.",[45,2283,2284],{"class":151},"SetLimit",[45,2286,330],{"class":155},[45,2288,2289],{"class":219},"10",[45,2291,2292],{"class":155},")  ",[45,2294,2295],{"class":51},"\u002F\u002F at most 10 concurrent goroutines\n",[45,2297,2298],{"class":47,"line":102},[45,2299,141],{"emptyLinePlaceholder":140},[45,2301,2302,2304,2307,2309,2311],{"class":47,"line":108},[45,2303,1218],{"class":147},[45,2305,2306],{"class":155}," i, url ",[45,2308,165],{"class":147},[45,2310,1467],{"class":147},[45,2312,2313],{"class":155}," urls {\n",[45,2315,2316,2319,2321,2324],{"class":47,"line":114},[45,2317,2318],{"class":155},"        i, url ",[45,2320,165],{"class":147},[45,2322,2323],{"class":155}," i, url  ",[45,2325,2326],{"class":51},"\u002F\u002F capture (pre-1.22; 1.22+ doesn't need this)\n",[45,2328,2329,2332,2335,2337,2339,2342,2344],{"class":47,"line":119},[45,2330,2331],{"class":155},"        g.",[45,2333,2334],{"class":151},"Go",[45,2336,330],{"class":155},[45,2338,148],{"class":147},[45,2340,2341],{"class":155},"() ",[45,2343,356],{"class":147},[45,2345,542],{"class":155},[45,2347,2348,2351,2353,2356],{"class":47,"line":125},[45,2349,2350],{"class":155},"            data, err ",[45,2352,165],{"class":147},[45,2354,2355],{"class":151}," fetch",[45,2357,2358],{"class":155},"(ctx, url)\n",[45,2360,2361,2363,2365,2367,2369],{"class":47,"line":131},[45,2362,1247],{"class":147},[45,2364,533],{"class":155},[45,2366,536],{"class":147},[45,2368,539],{"class":219},[45,2370,542],{"class":155},[45,2372,2373,2375,2378],{"class":47,"line":137},[45,2374,1258],{"class":147},[45,2376,2377],{"class":155}," err  ",[45,2379,2380],{"class":51},"\u002F\u002F cancels ctx and stops other goroutines\n",[45,2382,2383],{"class":47,"line":144},[45,2384,1268],{"class":155},[45,2386,2387,2390,2392,2395],{"class":47,"line":159},[45,2388,2389],{"class":155},"            results[i] ",[45,2391,292],{"class":147},[45,2393,2394],{"class":155}," data  ",[45,2396,2397],{"class":51},"\u002F\u002F safe — each goroutine writes a distinct index\n",[45,2399,2400,2402],{"class":47,"line":183},[45,2401,1377],{"class":147},[45,2403,2404],{"class":219}," nil\n",[45,2406,2407],{"class":47,"line":198},[45,2408,2409],{"class":155},"        })\n",[45,2411,2412],{"class":47,"line":203},[45,2413,557],{"class":155},[45,2415,2416],{"class":47,"line":229},[45,2417,141],{"emptyLinePlaceholder":140},[45,2419,2420,2422,2424,2426,2429,2432,2435,2437,2439],{"class":47,"line":240},[45,2421,530],{"class":147},[45,2423,533],{"class":155},[45,2425,165],{"class":147},[45,2427,2428],{"class":155}," g.",[45,2430,2431],{"class":151},"Wait",[45,2433,2434],{"class":155},"(); err ",[45,2436,536],{"class":147},[45,2438,539],{"class":219},[45,2440,542],{"class":155},[45,2442,2443,2445,2447,2450],{"class":47,"line":245},[45,2444,547],{"class":147},[45,2446,539],{"class":219},[45,2448,2449],{"class":155},", err  ",[45,2451,2452],{"class":51},"\u002F\u002F first error from any goroutine\n",[45,2454,2455],{"class":47,"line":274},[45,2456,557],{"class":155},[45,2458,2459,2461,2464],{"class":47,"line":280},[45,2460,398],{"class":147},[45,2462,2463],{"class":155}," results, ",[45,2465,1152],{"class":219},[45,2467,2468],{"class":47,"line":286},[45,2469,301],{"class":155},[28,2471,2473],{"id":2472},"tips-tricks","💡 Tips & Tricks",[2475,2476,2477,2500,2513,2532,2549,2556],"ul",{},[2478,2479,2480,2483,2484,2487,2488,2490,2491,2490,2493,2496,2497,2499],"li",{},[23,2481,2482],{},"Idiom",": always ",[18,2485,2486],{},"defer cancel()"," when using ",[18,2489,171],{},"\u002F",[18,2492,213],{},[18,2494,2495],{},"WithDeadline"," — releases resources (timers, goroutines) even if the operation completes normally. Forgetting ",[18,2498,307],{}," leaks.",[2478,2501,2502,2504,2505,2508,2509,2512],{},[23,2503,2482],{},": pass ",[18,2506,2507],{},"context.Context"," as the FIRST parameter of every function that does I\u002FO or can be canceled — ",[18,2510,2511],{},"func f(ctx context.Context, ...)",". This is the universal Go convention; libraries expect it.",[2478,2514,2515,2517,2518,2521,2522,2525,2526,2528,2529,2531],{},[23,2516,2482],{},": use ",[18,2519,2520],{},"context.Background()"," at the top level (main, tests) and ",[18,2523,2524],{},"r.Context()"," in HTTP handlers — ",[18,2527,177],{}," is the root; ",[18,2530,2524],{}," is canceled when the client disconnects.",[2478,2533,2534,2536,2537,2540,2541,2544,2545,2548],{},[23,2535,2482],{},": include ",[18,2538,2539],{},"\u003C-ctx.Done()"," in every long-running goroutine's ",[18,2542,2543],{},"select"," — it provides the exit path when the parent cancels. A goroutine that never checks ",[18,2546,2547],{},"ctx.Done()"," can't be canceled (leak).",[2478,2550,2551,2517,2553,2555],{},[23,2552,2482],{},[18,2554,255],{}," sparingly and only for cross-cutting concerns (request ID, trace ID) — it's untyped and encourages hidden coupling. Use a custom key type to avoid string collisions.",[2478,2557,2558,2560,2561,2563],{},[23,2559,2482],{},": don't store contexts in structs — they're for flowing through call chains, not fields. A struct with a ",[18,2562,435],{}," field breaks cancellation propagation.",[28,2565,2567],{"id":2566},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2475,2569,2570,2589,2598,2619,2632,2638,2653,2670,2679],{},[2478,2571,2572,1029,2578,2490,2580,2582,2583,2585,2586,2588],{},[23,2573,2574,2575,2577],{},"Forgetting ",[18,2576,307],{}," leaks",[18,2579,213],{},[18,2581,2495],{}," start a timer; not calling ",[18,2584,307],{}," leaves the timer alive until the deadline. ",[18,2587,2486],{}," is the fix.",[2478,2590,2591,2594,2595,2597],{},[23,2592,2593],{},"Don't store contexts in structs",": contexts are for passing through call chains, not for keeping in fields. A struct with a ",[18,2596,435],{}," field is a code smell.",[2478,2599,2600,1029,2605,2607,2608,2611,2612,2615,2616,2618],{},[23,2601,2602,2604],{},[18,2603,2547],{}," is a channel, not a value",[18,2606,2539],{}," blocks until canceled; ",[18,2609,2610],{},"ctx.Err()"," gives the reason. Don't poll ",[18,2613,2614],{},"Done()"," — ",[18,2617,2543],{}," on it.",[2478,2620,2621,2626,2627,2490,2629,2631],{},[23,2622,2623,2625],{},[18,2624,2520],{}," is never canceled",": it's the root. Derive from it with ",[18,2628,171],{},[18,2630,213],{}," for cancellation.",[2478,2633,2634,2637],{},[23,2635,2636],{},"Canceling a parent cancels children",": but canceling a child doesn't affect the parent or siblings. This is the tree structure.",[2478,2639,2640,1029,2645,2648,2649,2652],{},[23,2641,2642,2644],{},[18,2643,255],{}," is untyped",[18,2646,2647],{},"ctx.Value(key)"," returns ",[18,2650,2651],{},"any"," — must type-assert. Use a custom key type to avoid collisions.",[2478,2654,2655,1029,2663,2666,2667,2669],{},[23,2656,2657,2660,2661],{},[18,2658,2659],{},"context.TODO()"," vs ",[18,2662,2520],{},[18,2664,2665],{},"TODO"," signals \"I haven't decided which context to use yet\" — it's a placeholder. Use ",[18,2668,177],{}," for the actual root.",[2478,2671,2672,1029,2675,2678],{},[23,2673,2674],{},"Nil context is a panic",[18,2676,2677],{},"var ctx context.Context; ctx.Done()"," panics. Always pass a real context (Background at minimum).",[2478,2680,2681,1029,2687,2690,2691,2693],{},[23,2682,2683,2686],{},[18,2684,2685],{},"errgroup.WithContext"," cancels on first error",[18,2688,2689],{},"g.Go"," returns an error → the derived context is canceled → other goroutines see ",[18,2692,2539],{}," and exit. This is coordinated error handling.",[28,2695,2697],{"id":2696},"quick-quiz","🧠 Quick Quiz",[33,2699,2700,2806],{"language":35},[37,2701,2703],{"className":39,"code":2702,"language":35,"meta":41,"style":41},"func handler(ctx context.Context) {\n    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n    \u002F\u002F ⚠️ no defer cancel()\n\n    doWork(ctx)\n}\n\nfunc doWork(ctx context.Context) {\n    time.Sleep(10 * time.Second)\n}\n",[18,2704,2705,2723,2741,2746,2750,2758,2762,2766,2785,2802],{"__ignoreMap":41},[45,2706,2707,2709,2711,2713,2715,2717,2719,2721],{"class":47,"line":48},[45,2708,148],{"class":147},[45,2710,616],{"class":151},[45,2712,330],{"class":155},[45,2714,435],{"class":333},[45,2716,438],{"class":151},[45,2718,348],{"class":155},[45,2720,443],{"class":151},[45,2722,359],{"class":155},[45,2724,2725,2727,2729,2731,2733,2735,2737,2739],{"class":47,"line":55},[45,2726,470],{"class":155},[45,2728,165],{"class":147},[45,2730,168],{"class":155},[45,2732,213],{"class":151},[45,2734,479],{"class":155},[45,2736,220],{"class":219},[45,2738,223],{"class":147},[45,2740,226],{"class":155},[45,2742,2743],{"class":47,"line":61},[45,2744,2745],{"class":51},"    \u002F\u002F ⚠️ no defer cancel()\n",[45,2747,2748],{"class":47,"line":67},[45,2749,141],{"emptyLinePlaceholder":140},[45,2751,2752,2755],{"class":47,"line":73},[45,2753,2754],{"class":151},"    doWork",[45,2756,2757],{"class":155},"(ctx)\n",[45,2759,2760],{"class":47,"line":79},[45,2761,301],{"class":155},[45,2763,2764],{"class":47,"line":85},[45,2765,141],{"emptyLinePlaceholder":140},[45,2767,2768,2770,2773,2775,2777,2779,2781,2783],{"class":47,"line":91},[45,2769,148],{"class":147},[45,2771,2772],{"class":151}," doWork",[45,2774,330],{"class":155},[45,2776,435],{"class":333},[45,2778,438],{"class":151},[45,2780,348],{"class":155},[45,2782,443],{"class":151},[45,2784,359],{"class":155},[45,2786,2787,2790,2793,2795,2797,2799],{"class":47,"line":97},[45,2788,2789],{"class":155},"    time.",[45,2791,2792],{"class":151},"Sleep",[45,2794,330],{"class":155},[45,2796,2289],{"class":219},[45,2798,637],{"class":147},[45,2800,2801],{"class":155}," time.Second)\n",[45,2803,2804],{"class":47,"line":102},[45,2805,301],{"class":155},[14,2807,2808],{},"What's the problem?",[2810,2811,2812,2816,2821,2831,2843,2846,2856,2859],"details",{},[2813,2814,2815],"summary",{},"Answer",[14,2817,16,2818,2820],{},[18,2819,307],{}," function is never called — the timer leaks.",[14,2822,2823,2824,2827,2828,2830],{},"Even though ",[18,2825,2826],{},"doWork"," runs for 10 seconds (exceeding the 5-second timeout), the timer goroutine started by ",[18,2829,213],{}," lives until one of:",[2832,2833,2834,2840],"ol",{},[2478,2835,2836,2839],{},[18,2837,2838],{},"cancel()"," is called (never — it's discarded)",[2478,2841,2842],{},"The deadline elapses (5 seconds)",[14,2844,2845],{},"So the timer stops after 5 seconds (the deadline fires). But this is by luck — if the work had completed in 100ms, the timer would linger for 4.9 seconds, wasting resources.",[14,2847,2848,2849,2852,2853,2855],{},"The real problem: if ",[18,2850,2851],{},"handler"," is called thousands of times per second (it's an HTTP handler), each call starts a timer. Without ",[18,2854,307],{},", thousands of timer goroutines accumulate.",[14,2857,2858],{},"The fix:",[37,2860,2862],{"className":39,"code":2861,"language":35,"meta":41,"style":41},"func handler(ctx context.Context) {\n    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)\n    defer cancel()  \u002F\u002F ✅ releases the timer immediately when handler returns\n\n    doWork(ctx)\n}\n",[18,2863,2864,2882,2900,2911,2915,2921],{"__ignoreMap":41},[45,2865,2866,2868,2870,2872,2874,2876,2878,2880],{"class":47,"line":48},[45,2867,148],{"class":147},[45,2869,616],{"class":151},[45,2871,330],{"class":155},[45,2873,435],{"class":333},[45,2875,438],{"class":151},[45,2877,348],{"class":155},[45,2879,443],{"class":151},[45,2881,359],{"class":155},[45,2883,2884,2886,2888,2890,2892,2894,2896,2898],{"class":47,"line":55},[45,2885,470],{"class":155},[45,2887,165],{"class":147},[45,2889,168],{"class":155},[45,2891,213],{"class":151},[45,2893,479],{"class":155},[45,2895,220],{"class":219},[45,2897,223],{"class":147},[45,2899,226],{"class":155},[45,2901,2902,2904,2906,2908],{"class":47,"line":61},[45,2903,186],{"class":147},[45,2905,189],{"class":151},[45,2907,192],{"class":155},[45,2909,2910],{"class":51},"\u002F\u002F ✅ releases the timer immediately when handler returns\n",[45,2912,2913],{"class":47,"line":67},[45,2914,141],{"emptyLinePlaceholder":140},[45,2916,2917,2919],{"class":47,"line":73},[45,2918,2754],{"class":151},[45,2920,2757],{"class":155},[45,2922,2923],{"class":47,"line":79},[45,2924,301],{"class":155},[28,2926,2928],{"id":2927},"whats-next","📚 What's Next",[14,2930,2931,2932,2937,2938,2941],{},"→ ",[2933,2934,2936],"a",{"href":2935},"\u002Fgo\u002F21-packages-and-modules","21 — Packages & Modules"," — module versioning, ",[18,2939,2940],{},"internal\u002F"," enforcement, workspaces, and versioning semantics.",[2943,2944,2945],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":41,"searchDepth":55,"depth":55,"links":2947},[2948,2949,2951],{"id":30,"depth":55,"text":31},{"id":304,"depth":55,"text":2950},"The cancel Leak — The #1 Context Bug",{"id":2927,"depth":55,"text":2928},"Cancellation trees, deadlines, request-scoped values, the cancel-leak pattern, and context propagation through API boundaries.","md",{},"\u002Fgo\u002F20-context",{"title":5,"description":2952},"go\u002F20-context","h3AMYVcP-go255-FaVqtMhyiaRy0HsgmkND1AiuuIh8",1789924648619]