[{"data":1,"prerenderedAt":910},["ShallowReactive",2],{"navigation":3,"/blog/postmortem-worker-db-connection-hang":130,"surround-postmortem-worker-db-connection-hang":898},[4],{"title":5,"path":6,"stem":7,"children":8,"page":129},"Blog","/blog","blog",[9,13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125],{"title":10,"path":11,"stem":12},"How to Increase Free Tier Memory on AWS EC2","/blog/aws-ec2-ram","blog/aws-ec2-ram",{"title":14,"path":15,"stem":16},"Blooper: The Disappearing Cloudflare Variables","/blog/blooper-cloudflare-env-vars","blog/blooper-cloudflare-env-vars",{"title":18,"path":19,"stem":20},"Blooper: Hardcoded Content Links cause 404s","/blog/blooper-hardcoded-nuxt-content-links","blog/blooper-hardcoded-nuxt-content-links",{"title":22,"path":23,"stem":24},"Blooper: The Invisible SEO","/blog/blooper-nuxt-seo-env","blog/blooper-nuxt-seo-env",{"title":26,"path":27,"stem":28},"Blooper: The SSR Crash of Doom","/blog/blooper-ssr-feedback-form","blog/blooper-ssr-feedback-form",{"title":30,"path":31,"stem":32},"Blooper: The YouTube Crawl Budget Killer","/blog/blooper-video-crawl-budget","blog/blooper-video-crawl-budget",{"title":34,"path":35,"stem":36},"Blooper: PWA Redirecting SPA Routes","/blog/blooper-vite-pwa-ssr-redirects","blog/blooper-vite-pwa-ssr-redirects",{"title":38,"path":39,"stem":40},"Disk Management in Linux","/blog/disk-management-in-linux","blog/disk-management-in-linux",{"title":42,"path":43,"stem":44},"Docker Devtools Stage | Powerlevel, OhMyZSH, tmux, fuzzy finder, autocomplete etc","/blog/docker-devtools","blog/docker-devtools",{"title":46,"path":47,"stem":48},"Docker container | Resolving Permission Denied Woes: A Decade-Long Struggle Unraveled","/blog/docker-non-root-user-perms","blog/docker-non-root-user-perms",{"title":50,"path":51,"stem":52},"Git commands | underrated","/blog/git-commands-underrated","blog/git-commands-underrated",{"title":54,"path":55,"stem":56},"Journey: Taming Edge Caching and KV Storage","/blog/journey-github-streak-caching","blog/journey-github-streak-caching",{"title":58,"path":59,"stem":60},"Kubernetes Cluster Setup Guide","/blog/k8s-setup","blog/k8s-setup",{"title":62,"path":63,"stem":64},"Linux WiFi Drivers","/blog/linux-wifi-drivers","blog/linux-wifi-drivers",{"title":66,"path":67,"stem":68},"pfSense basic firewall setup","/blog/pfsense-basic-firewall-setup","blog/pfsense-basic-firewall-setup",{"title":70,"path":71,"stem":72},"pfSense Quickstart","/blog/pfsense-quickstart","blog/pfsense-quickstart",{"title":74,"path":75,"stem":76},"Postmortem: Cloudflare Worker Missing Dependency on Deploy","/blog/postmortem-cloudflare-worker-dependency-deploy","blog/postmortem-cloudflare-worker-dependency-deploy",{"title":78,"path":79,"stem":80},"Postmortem: Serverless HTTP Driver Transaction Failures","/blog/postmortem-neon-http-transactions","blog/postmortem-neon-http-transactions",{"title":82,"path":83,"stem":84},"Postmortem: Nuxt Content 404s on Staging Deployments","/blog/postmortem-nuxt-content-404-staging","blog/postmortem-nuxt-content-404-staging",{"title":86,"path":87,"stem":88},"Postmortem: 500 Internal Server Error on ISR Routes","/blog/postmortem-nuxt-content-payload-extraction","blog/postmortem-nuxt-content-payload-extraction",{"title":90,"path":91,"stem":92},"Post-Mortem: Intrusive Database Driver Refactoring","/blog/postmortem-proxy-re-architecting","blog/postmortem-proxy-re-architecting",{"title":94,"path":95,"stem":96},"Post-Mortem: Cloudflare Worker Connection Hang & Resilient DB Fallbacks","/blog/postmortem-worker-db-connection-hang","blog/postmortem-worker-db-connection-hang",{"title":98,"path":99,"stem":100},"Pro Tip: Sandboxing Cloudflare Workers for AI Agents","/blog/pro-tip-wrangler-local-dev-trick","blog/pro-tip-wrangler-local-dev-trick",{"title":102,"path":103,"stem":104},"Proxmox DNS Management","/blog/proxmox-dns","blog/proxmox-dns",{"title":106,"path":107,"stem":108},"Proxmox Recovery","/blog/proxmox-recovery","blog/proxmox-recovery",{"title":110,"path":111,"stem":112},"Proxmox WiFi Connection Story","/blog/proxmox-wifi","blog/proxmox-wifi",{"title":114,"path":115,"stem":116},"roadauth-rails api jwt cors","/blog/rodauth-jwt","blog/rodauth-jwt",{"title":118,"path":119,"stem":120},"SOCKS5 Proxy Quickstart","/blog/sock5-proxy","blog/sock5-proxy",{"title":122,"path":123,"stem":124},"tmux status bar toggle","/blog/tmux-status","blog/tmux-status",{"title":126,"path":127,"stem":128},"UFW - Cheatsheet","/blog/ufw-cheatsheet","blog/ufw-cheatsheet",false,{"id":131,"title":94,"authors":132,"badge":138,"body":140,"date":888,"description":889,"extension":890,"image":891,"imageComponent":892,"meta":893,"navigation":517,"path":95,"pinned":129,"seo":894,"seoImage":895,"stem":96,"__hash__":897},"posts/blog/postmortem-worker-db-connection-hang.md",[133],{"name":134,"to":135,"avatar":136},"Rahul Dhole","/",{"src":137},"/profile.png",{"label":139},"Postmortem",{"type":141,"value":142,"toc":870},"minimark",[143,148,165,172,175,179,184,216,218,222,230,233,337,354,367,371,374,378,393,395,399,403,406,449,455,459,462,728,732,735,833,835,839,866],[144,145,147],"h2",{"id":146},"executive-summary","Executive Summary",[149,150,151,152,156,157,160,161,164],"p",{},"In production, a core API endpoint was encountering severe stability issues: crashing with ",[153,154,155],"code",{},"500 Internal Server Error"," and triggering ",[153,158,159],{},"1101 Worker Code Hung"," exceptions from the Cloudflare Workers runtime. The root cause was twofold: (1) a ",[153,162,163],{},"30000","ms (30s) connection pool idle timeout that kept WebSockets active indefinitely—violating Cloudflare’s stateless suspension model—and (2) a lack of query safety in the API handler, which crashed when database connections failed or when dates were returned as raw strings.",[149,166,167,168,171],{},"Both issues were resolved by aggressively reducing the database connection pool idle timeout to ",[153,169,170],{},"1000","ms, wrapping database operations in a try-catch fallback pattern, and safe-guarding date serialization.",[173,174],"hr",{},[144,176,178],{"id":177},"the-incident","The Incident",[180,181,183],"h3",{"id":182},"symptoms-timeline","Symptoms & Timeline",[185,186,187,195,210],"ol",{},[188,189,190,194],"li",{},[191,192,193],"strong",{},"Immediate Crashing (500):"," Requests to the API endpoint immediately failed in production with 500 errors.",[188,196,197,200,201],{},[191,198,199],{},"Workers Runtime Hangs (1101):"," The Cloudflare Workers runtime terminated incoming requests with the error:\n",[202,203,204],"blockquote",{},[149,205,206],{},[207,208,209],"em",{},"“The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response.”",[188,211,212,215],{},[191,213,214],{},"Investigation:"," The unit tests were passing locally in standard Node environments, masking the specific architectural and serverless-related pitfalls under Cloudflare Workers.",[173,217],{},[144,219,221],{"id":220},"root-cause-analysis","Root Cause Analysis",[180,223,225,226,229],{"id":224},"_1-the-event-loop-hang-idletimeoutmillis","1. The Event Loop Hang (",[153,227,228],{},"idleTimeoutMillis",")",[149,231,232],{},"To handle database cold starts, the connection pool was configured with:",[234,235,240],"pre",{"className":236,"code":237,"language":238,"meta":239,"style":239},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const pool = new Pool({\n  connectionString,\n  connectionTimeoutMillis: 10000,\n  max: 10,\n  idleTimeoutMillis: 30000, // 30 seconds\n})\n","typescript","",[153,241,242,272,281,297,310,328],{"__ignoreMap":239},[243,244,247,251,255,259,262,266,269],"span",{"class":245,"line":246},"line",1,[243,248,250],{"class":249},"spNyl","const",[243,252,254],{"class":253},"sTEyZ"," pool ",[243,256,258],{"class":257},"sMK4o","=",[243,260,261],{"class":257}," new",[243,263,265],{"class":264},"s2Zo4"," Pool",[243,267,268],{"class":253},"(",[243,270,271],{"class":257},"{\n",[243,273,275,278],{"class":245,"line":274},2,[243,276,277],{"class":253},"  connectionString",[243,279,280],{"class":257},",\n",[243,282,284,288,291,295],{"class":245,"line":283},3,[243,285,287],{"class":286},"swJcz","  connectionTimeoutMillis",[243,289,290],{"class":257},":",[243,292,294],{"class":293},"sbssI"," 10000",[243,296,280],{"class":257},[243,298,300,303,305,308],{"class":245,"line":299},4,[243,301,302],{"class":286},"  max",[243,304,290],{"class":257},[243,306,307],{"class":293}," 10",[243,309,280],{"class":257},[243,311,313,316,318,321,324],{"class":245,"line":312},5,[243,314,315],{"class":286},"  idleTimeoutMillis",[243,317,290],{"class":257},[243,319,320],{"class":293}," 30000",[243,322,323],{"class":257},",",[243,325,327],{"class":326},"sHwdD"," // 30 seconds\n",[243,329,331,334],{"class":245,"line":330},6,[243,332,333],{"class":257},"}",[243,335,336],{"class":253},")\n",[149,338,339,340,343,344,347,348,353],{},"While this keeps connections warm in standard Node environments, in Cloudflare Workers ",[191,341,342],{},"WebSockets must not be kept active indefinitely",". An idle timeout of 30 seconds meant active WebSockets remained in the event loop well after the request finished. Because the event loop never emptied, the Cloudflare Workers runtime assumed the code had hung and aborted the workers with a severe ",[191,345,346],{},"1101 error"," (",[349,350,352],"a",{"href":351},"#fig-1","Figure 1",").",[149,355,356,359,364],{},[349,357],{"id":358},"fig-1",[360,361],"mermaid",{":config":362,"code":363},"config","sequenceDiagram%0A%20%20%20%20participant%20Client%0A%20%20%20%20participant%20Worker%20as%20Cloudflare%20Worker%0A%20%20%20%20participant%20DB%20as%20Database%20Pool%0A%0A%20%20%20%20Client-%3E%3EWorker%3A%20API%20Request%0A%20%20%20%20Worker-%3E%3EDB%3A%20Query%0A%20%20%20%20DB--%3E%3EWorker%3A%20Result%0A%20%20%20%20Worker--%3E%3EClient%3A%20Response%0A%20%20%20%20Note%20over%20Worker%2CDB%3A%20Connection%20goes%20idle%20(30s%20timeout)%0A%20%20%20%20Note%20over%20Worker%3A%20Worker%20tries%20to%20suspend...%0A%20%20%20%20Note%20over%20Worker%3A%20Event%20loop%20not%20empty!%0A%20%20%20%20Worker--xWorker%3A%201101%20Worker%20Code%20Hung%20(Crash)",[207,365,366],{},"Figure 1: Worker event loop crash due to idle WebSocket connection",[180,368,370],{"id":369},"_2-lack-of-resilient-db-fallbacks","2. Lack of Resilient DB Fallbacks",[149,372,373],{},"Unlike other endpoints, this specific endpoint had no guardrails around database connection failures. If the serverless database was waking up (cold start) or temporarily unreachable, the database query failed, triggering a generic HTTP 500.",[180,375,377],{"id":376},"_3-date-serialization-crash","3. Date Serialization Crash",[149,379,380,381,384,385,388,389,392],{},"Depending on how the serverless driver returned query records, timestamp fields were sometimes returned as a string rather than a JavaScript ",[153,382,383],{},"Date"," object. Calling ",[153,386,387],{},".toISOString()"," on a string threw a ",[153,390,391],{},"TypeError",", causing a synchronous crash.",[173,394],{},[144,396,398],{"id":397},"resolution","Resolution",[180,400,402],{"id":401},"_1-websocket-pool-optimization","1. WebSocket Pool Optimization",[149,404,405],{},"We modified the database configuration to aggressively prune connection resources:",[234,407,411],{"className":408,"code":409,"language":410,"meta":239,"style":239},"language-diff shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","   const pool = new Pool({ \n     connectionString,\n     connectionTimeoutMillis: 10000,\n     max: 10,                        \n-    idleTimeoutMillis: 30000,       \n+    idleTimeoutMillis: 1000,        // Let the event loop empty so Worker suspends safely\n   })\n","diff",[153,412,413,418,423,428,433,438,443],{"__ignoreMap":239},[243,414,415],{"class":245,"line":246},[243,416,417],{},"   const pool = new Pool({ \n",[243,419,420],{"class":245,"line":274},[243,421,422],{},"     connectionString,\n",[243,424,425],{"class":245,"line":283},[243,426,427],{},"     connectionTimeoutMillis: 10000,\n",[243,429,430],{"class":245,"line":299},[243,431,432],{},"     max: 10,                        \n",[243,434,435],{"class":245,"line":312},[243,436,437],{},"-    idleTimeoutMillis: 30000,       \n",[243,439,440],{"class":245,"line":330},[243,441,442],{},"+    idleTimeoutMillis: 1000,        // Let the event loop empty so Worker suspends safely\n",[243,444,446],{"class":245,"line":445},7,[243,447,448],{},"   })\n",[149,450,451,452,454],{},"By reducing the idle timeout to ",[153,453,170],{},"ms, all active WebSockets are aggressively closed after queries complete. The event loop is permitted to empty, allowing Cloudflare Workers to suspend/resume gracefully.",[180,456,458],{"id":457},"_2-resilient-api-try-catch-fallback","2. Resilient API Try-Catch Fallback",[149,460,461],{},"We refactored the endpoint logic to intercept database-level failures and gracefully fallback to clean, default states:",[234,463,465],{"className":236,"code":464,"language":238,"meta":239,"style":239},"  let maxCount = 1\n  let results: any[] = []\n  let total = 0\n\n  try {\n    const db = getDb(event)\n    // Fetch limits and perform the main query\n    const listResult = await DataModel.list(event, userId, { page, limit, filter })\n    results = listResult.items || []\n    total = listResult.total || 0\n  } catch (dbErr) {\n    console.error('⚠️ Database query error, falling back to safe defaults:', dbErr)\n    maxCount = 1 // Standard fallback limit\n    results = []\n    total = 0\n  }\n",[153,466,467,480,501,513,519,528,549,554,608,628,647,661,690,704,713,722],{"__ignoreMap":239},[243,468,469,472,475,477],{"class":245,"line":246},[243,470,471],{"class":249},"  let",[243,473,474],{"class":253}," maxCount ",[243,476,258],{"class":257},[243,478,479],{"class":293}," 1\n",[243,481,482,484,487,489,493,496,498],{"class":245,"line":274},[243,483,471],{"class":249},[243,485,486],{"class":253}," results",[243,488,290],{"class":257},[243,490,492],{"class":491},"sBMFI"," any",[243,494,495],{"class":253},"[] ",[243,497,258],{"class":257},[243,499,500],{"class":253}," []\n",[243,502,503,505,508,510],{"class":245,"line":283},[243,504,471],{"class":249},[243,506,507],{"class":253}," total ",[243,509,258],{"class":257},[243,511,512],{"class":293}," 0\n",[243,514,515],{"class":245,"line":299},[243,516,518],{"emptyLinePlaceholder":517},true,"\n",[243,520,521,525],{"class":245,"line":312},[243,522,524],{"class":523},"s7zQu","  try",[243,526,527],{"class":257}," {\n",[243,529,530,533,536,539,542,544,547],{"class":245,"line":330},[243,531,532],{"class":249},"    const",[243,534,535],{"class":253}," db",[243,537,538],{"class":257}," =",[243,540,541],{"class":264}," getDb",[243,543,268],{"class":286},[243,545,546],{"class":253},"event",[243,548,336],{"class":286},[243,550,551],{"class":245,"line":445},[243,552,553],{"class":326},"    // Fetch limits and perform the main query\n",[243,555,557,559,562,564,567,570,573,576,578,580,582,585,587,590,593,595,598,600,603,606],{"class":245,"line":556},8,[243,558,532],{"class":249},[243,560,561],{"class":253}," listResult",[243,563,538],{"class":257},[243,565,566],{"class":523}," await",[243,568,569],{"class":253}," DataModel",[243,571,572],{"class":257},".",[243,574,575],{"class":264},"list",[243,577,268],{"class":286},[243,579,546],{"class":253},[243,581,323],{"class":257},[243,583,584],{"class":253}," userId",[243,586,323],{"class":257},[243,588,589],{"class":257}," {",[243,591,592],{"class":253}," page",[243,594,323],{"class":257},[243,596,597],{"class":253}," limit",[243,599,323],{"class":257},[243,601,602],{"class":253}," filter",[243,604,605],{"class":257}," }",[243,607,336],{"class":286},[243,609,611,614,616,618,620,623,626],{"class":245,"line":610},9,[243,612,613],{"class":253},"    results",[243,615,538],{"class":257},[243,617,561],{"class":253},[243,619,572],{"class":257},[243,621,622],{"class":253},"items",[243,624,625],{"class":257}," ||",[243,627,500],{"class":286},[243,629,631,634,636,638,640,643,645],{"class":245,"line":630},10,[243,632,633],{"class":253},"    total",[243,635,538],{"class":257},[243,637,561],{"class":253},[243,639,572],{"class":257},[243,641,642],{"class":253},"total",[243,644,625],{"class":257},[243,646,512],{"class":293},[243,648,650,653,656,659],{"class":245,"line":649},11,[243,651,652],{"class":257},"  }",[243,654,655],{"class":523}," catch",[243,657,658],{"class":253}," (dbErr) ",[243,660,271],{"class":257},[243,662,664,667,669,672,674,677,681,683,685,688],{"class":245,"line":663},12,[243,665,666],{"class":253},"    console",[243,668,572],{"class":257},[243,670,671],{"class":264},"error",[243,673,268],{"class":286},[243,675,676],{"class":257},"'",[243,678,680],{"class":679},"sfazB","⚠️ Database query error, falling back to safe defaults:",[243,682,676],{"class":257},[243,684,323],{"class":257},[243,686,687],{"class":253}," dbErr",[243,689,336],{"class":286},[243,691,693,696,698,701],{"class":245,"line":692},13,[243,694,695],{"class":253},"    maxCount",[243,697,538],{"class":257},[243,699,700],{"class":293}," 1",[243,702,703],{"class":326}," // Standard fallback limit\n",[243,705,707,709,711],{"class":245,"line":706},14,[243,708,613],{"class":253},[243,710,538],{"class":257},[243,712,500],{"class":286},[243,714,716,718,720],{"class":245,"line":715},15,[243,717,633],{"class":253},[243,719,538],{"class":257},[243,721,512],{"class":293},[243,723,725],{"class":245,"line":724},16,[243,726,727],{"class":257},"  }\n",[180,729,731],{"id":730},"_3-safe-date-stringification","3. Safe Date Stringification",[149,733,734],{},"We safe-guarded the date serialization mapping so it dynamically handles strings or missing dates:",[234,736,738],{"className":236,"code":737,"language":238,"meta":239,"style":239},"updatedAt: row.updatedAt instanceof Date \n  ? row.updatedAt.toISOString() \n  : (row.updatedAt ? new Date(row.updatedAt).toISOString() : new Date().toISOString())\n",[153,739,740,764,783],{"__ignoreMap":239},[243,741,742,745,747,750,752,755,758,761],{"class":245,"line":246},[243,743,744],{"class":491},"updatedAt",[243,746,290],{"class":257},[243,748,749],{"class":253}," row",[243,751,572],{"class":257},[243,753,754],{"class":253},"updatedAt ",[243,756,757],{"class":257},"instanceof",[243,759,760],{"class":491}," Date",[243,762,763],{"class":253}," \n",[243,765,766,769,771,773,775,777,780],{"class":245,"line":274},[243,767,768],{"class":257},"  ?",[243,770,749],{"class":253},[243,772,572],{"class":257},[243,774,744],{"class":253},[243,776,572],{"class":257},[243,778,779],{"class":264},"toISOString",[243,781,782],{"class":253},"() \n",[243,784,785,788,791,793,795,798,800,802,805,807,810,812,814,817,819,821,823,826,828,830],{"class":245,"line":283},[243,786,787],{"class":257},"  :",[243,789,790],{"class":253}," (row",[243,792,572],{"class":257},[243,794,754],{"class":253},[243,796,797],{"class":257},"?",[243,799,261],{"class":257},[243,801,760],{"class":264},[243,803,804],{"class":253},"(row",[243,806,572],{"class":257},[243,808,809],{"class":253},"updatedAt)",[243,811,572],{"class":257},[243,813,779],{"class":264},[243,815,816],{"class":253},"() ",[243,818,290],{"class":257},[243,820,261],{"class":257},[243,822,760],{"class":264},[243,824,825],{"class":253},"()",[243,827,572],{"class":257},[243,829,779],{"class":264},[243,831,832],{"class":253},"())\n",[173,834],{},[144,836,838],{"id":837},"lessons-learned-prevention","Lessons Learned & Prevention",[185,840,841,850,856],{},[188,842,843,846,847,849],{},[191,844,845],{},"Be Mindful of the Event Loop in Serverless:"," Never keep WebSockets, timeouts, or interval loops active past the lifecycle of a request in Cloudflare Workers. Keep idle timeouts as low as possible (",[153,848,170],{},"ms) to allow the event loop to empty.",[188,851,852,855],{},[191,853,854],{},"Defensive API Patterns:"," Wrap user-critical page loads in robust try-catch fallbacks. Users should still be able to load empty states or free-tier experiences gracefully during database cold starts or transient connection errors.",[188,857,858,861,862,865],{},[191,859,860],{},"Safe String/Object Casting:"," Never assume database drivers will return native JS Date objects in all environments. Always perform type validation or wrapper checks (",[153,863,864],{},"instanceof Date",") before calling date-specific methods.",[867,868,869],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":239,"searchDepth":274,"depth":274,"links":871},[872,873,876,882,887],{"id":146,"depth":274,"text":147},{"id":177,"depth":274,"text":178,"children":874},[875],{"id":182,"depth":283,"text":183},{"id":220,"depth":274,"text":221,"children":877},[878,880,881],{"id":224,"depth":283,"text":879},"1. The Event Loop Hang (idleTimeoutMillis)",{"id":369,"depth":283,"text":370},{"id":376,"depth":283,"text":377},{"id":397,"depth":274,"text":398,"children":883},[884,885,886],{"id":401,"depth":283,"text":402},{"id":457,"depth":283,"text":458},{"id":730,"depth":283,"text":731},{"id":837,"depth":274,"text":838},"2026-05-27","Resolving Cloudflare Worker connection hangs caused by database connection pools and missing API fallbacks.","md",null,{"type":139},{},{"title":94,"description":889},{"src":896},"https://placehold.co/800x400/0f172a/3b82f6?text=Worker+Connection+Hang","mDFiXZ1EjS3mS5alJuPBoDZq4d7GcwEiFwP5zKu1PQU",[899,904],{"title":90,"path":91,"stem":92,"description":900,"imageComponent":901,"seoImage":902,"children":-1},"A post-mortem on handling architectural integrity when an AI assistant performs an unauthorized database driver refactoring.",{"type":139},{"src":903},"https://placehold.co/800x400/0f172a/3b82f6?text=Post-Mortem:+Intrusive+Database+Driver+Refactoring",{"title":98,"path":99,"stem":100,"description":905,"imageComponent":906,"seoImage":908,"children":-1},"How to safely sandbox your Cloudflare Workers environment when working with AI coding agents.",{"type":907},"Pro Tip",{"src":909},"https://placehold.co/800x400/0f172a/3b82f6?text=Sandboxing+Cloudflare+Workers",1784464469177]