<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>A Million and One Moos Blog</title>
        <link>https://your-docusaurus-site.example.com/</link>
        <description>A Million and One Moos Blog</description>
        <lastBuildDate>Sun, 10 May 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[All Naive Service Workers Eventually Die]]></title>
            <link>https://your-docusaurus-site.example.com/postmortem-service-worker-timeout</link>
            <guid>https://your-docusaurus-site.example.com/postmortem-service-worker-timeout</guid>
            <pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A Post-Mortem on Offline-First Web Apps under Intermittent Connectivity]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-post-mortem-on-offline-first-web-apps-under-intermittent-connectivity">A Post-Mortem on Offline-First Web Apps under Intermittent Connectivity<a href="https://your-docusaurus-site.example.com/postmortem-service-worker-timeout#a-post-mortem-on-offline-first-web-apps-under-intermittent-connectivity" class="hash-link" aria-label="Direct link to A Post-Mortem on Offline-First Web Apps under Intermittent Connectivity" title="Direct link to A Post-Mortem on Offline-First Web Apps under Intermittent Connectivity" translate="no">​</a></h2>
<p style="text-align:center"></p><p>بسم الله الرحمن الرحيم</p><p></p>
<p>Not too long ago, I was visiting a local mosque (and community center) that I frequent and noticed that the slideshow display in the main hall wasn’t working. After some discussion with one of the admins, we proposed a new slideshow display to replace their defunct display they had at the time. The new display would be a web app that achieves feature-parity with the previous version and adds some extra conveniences.</p>
<p>The first version of the slideshow was deployed to the center just a couple of days after the proposal. About 16 hours later, I received the first complaint:</p>
<!-- -->
<p>“Hey, it seems the slideshow has stopped working?“</p>
<p>Attached was a photo that looked something like this:</p>
<p><img decoding="async" loading="lazy" alt="Firefox no connection" src="https://your-docusaurus-site.example.com/assets/images/ff-no-conn-e65dc6f262d0280cc44d875edf34f553.png" width="1920" height="1012" class="img_ev3q"></p>
<p>I was bewildered, as the device running the slideshow had around-the-clock network access via ethernet. After some testing it appeared that the center’s internet was significantly poorer than expected. Multiple times per day, the internet connection would drop for minutes at a time despite using ethernet.</p>
<p>Knowing this, I could have taken the simple route and packaged the app in <a href="https://www.electronjs.org/" target="_blank" rel="noopener noreferrer" class="">Electron</a> or <a href="https://tauri.app/" target="_blank" rel="noopener noreferrer" class="">Tauri</a> and effectively bypassed this issue entirely. However, this would make updates significantly more difficult, so I decided it wasn’t the right solution.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-notorious-service-worker">The Notorious Service Worker<a href="https://your-docusaurus-site.example.com/postmortem-service-worker-timeout#the-notorious-service-worker" class="hash-link" aria-label="Direct link to The Notorious Service Worker" title="Direct link to The Notorious Service Worker" translate="no">​</a></h2>
<p>This is when I was introduced to the main hero (and villain?) of the post, the notorious <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers" target="_blank" rel="noopener noreferrer" class="">Service Worker</a> (SW). Simply put, a SW is a background thread that intercepts HTTP requests made by a web app <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#registering_your_worker" target="_blank" rel="noopener noreferrer" class="">within its scope</a>. Whenever a request is made, the SW is notified and can decide how to handle it. It can allow the request to continue as usual, return a file stored on the user's file system, transform the request to fetch a resource from another domain, etc. The possibilities are endless here really. Here’s a quick example of a SW:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// serviceWorker.js</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">addEventListener</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"fetch"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token arrow operator" style="color:#393A34">=&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  event</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">respondWith</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">handleRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> event</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> cached </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> caches</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">match</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// if not saved on local file system fetch from network</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">cached</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> cached</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// index.js</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token dom variable" style="color:#36acaa">navigator</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">serviceWorker</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">register</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/serviceWorker.js'</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>After some quick research on SWs, I decided they are right choice for this project. It wouldn't require any significant architectural changes and updates would be easy-peasy. Only 3 changes were needed:</p>
<ol>
<li class="">Every time the root <code>index.html</code> page is requested it should be fetched via network and cached for later use. If the request fails, have the SW return the cached version (aka <a href="https://developer.chrome.com/docs/workbox/caching-strategies-overview/#network_first_falling_back_to_cache" target="_blank" rel="noopener noreferrer" class="">network-first policy</a>).</li>
<li class="">During startup or after a refresh, the app would cache all source files (css, js, images, etc.) and delete any stale files. If a source file is found on disk have the SW return it, otherwise request it via network (aka <a href="https://developer.chrome.com/docs/workbox/caching-strategies-overview/#cache_first_falling_back_to_network" target="_blank" rel="noopener noreferrer" class="">cache-first policy</a>). For this to work correctly all source files should be hashed, which automatically occurs with build tools like <a href="https://vite.dev/" target="_blank" rel="noopener noreferrer" class="">Vite</a>.</li>
<li class="">Every once in a while, maybe an hour or so, update the app by refreshing the window using something like the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/reload" target="_blank" rel="noopener noreferrer" class=""><code>location.reload</code></a> API.</li>
</ol>
<p>With these changes, the app would fall back to the older cached version under poor network conditions and try again later. This should have prevented poor network conditions from crashing the app, or so I thought…</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="firefox-puts-you-in-the-timeout-corner">Firefox Puts You in the Timeout Corner<a href="https://your-docusaurus-site.example.com/postmortem-service-worker-timeout#firefox-puts-you-in-the-timeout-corner" class="hash-link" aria-label="Direct link to Firefox Puts You in the Timeout Corner" title="Direct link to Firefox Puts You in the Timeout Corner" translate="no">​</a></h2>
<p>Just 48 hours later after deploying the updated app with a SW and manually restarting the slideshow I received a message (at 6AM no less) about the slideshow not displaying any content, with this image attached:</p>
<p><img decoding="async" loading="lazy" alt="Firefox Timeout Screen" src="https://your-docusaurus-site.example.com/assets/images/ff-timeout-b0d6308a563ac8219d654d55f6b8a7f9.jpeg" width="1000" height="750" class="img_ev3q"></p>
<p>This left me more confused than the previous time. I had accounted for poor network conditions and expected that files be served from cache under those conditions and <strong>NOT</strong> crash the app. However, upon further investigation it appeared I had forgotten to account for one sneaky edge case: when the network is technically connected but a request hangs for too long, forcing the user-agent (Firefox browser in this case) to kill the SW.</p>
<p>Discussions online seem to indicate that the upper bound for SW activity, including HTTP requests, is <a href="https://github.com/w3c/ServiceWorker/issues/1182" target="_blank" rel="noopener noreferrer" class="">5 minutes</a>. In other words, if a SW performs a network request for longer than 5 minutes the user-agent will kill the request and return an error. However, in my testing, Firefox consistently killed the SW after ~90 seconds and returned the lovely error you see in the screenshot above.</p>
<p>Now you can probably imagine the full extent of the disaster. With my previous SW implementation if <strong>ANY</strong> request for the root <code>index.html</code> page times out and is killed by the user-agent, an error response is returned. This would occur even if every app file - including the older cached version of <code>index.html</code> - were  already cached on disk! In fact, even if the entire <code>handleRequest</code> function in the SW were wrapped in a try-catch block (which mine was) the result would be the same.</p>
<p>The solution? Add timeouts to SW requests that are shorter than the user-agent’s maximum timeout. Continuing from the previous example, update the <code>handleRequest</code> function like so:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">TIMEOUT_MILLIS</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30_000</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 30 seconds</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">INDEX_NOT_CACHED_RES</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">Response</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token string" style="color:#e3116c">"failed to get index.html"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token literal-property property" style="color:#36acaa">status</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">500</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">statusText</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"NET ERR"</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">handleRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> event</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> url </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">URL</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">url</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> isRootPage </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      url</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pathname</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/"</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> url</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pathname</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"index.html"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">isRootPage </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> url</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">origin</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">===</span><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">location</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">origin</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token comment" style="color:#999988;font-style:italic">// prevent the user-agent from killing the request</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token literal-property property" style="color:#36acaa">signal</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">AbortSignal</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">timeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">TIMEOUT_MILLIS</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> cachedRoot </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> caches</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">match</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> cachedRoot </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">INDEX_NOT_CACHED_RES</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> cached </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">await</span><span class="token plain"> caches</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">match</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">cached</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">fetch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// optional, but results in better UX</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token literal-property property" style="color:#36acaa">signal</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token maybe-class-name">AbortSignal</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">timeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token constant" style="color:#36acaa">TIMEOUT_MILLIS</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> cached</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>After adding these few lines of code and manually restarting the slideshow for a second time a few weeks ago, I haven't received any complaints or angry 6AM messages. Phew, peace at last!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://your-docusaurus-site.example.com/postmortem-service-worker-timeout#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>The takeaway: add timeouts to your SW requests, especially when using a network-first strategy. This is particularly true if you need to create truly offline-first web apps that are resilient to poor network conditions.</p>
<p>Another lesson I learned is that you should think twice before using a conventional webpage for apps that need to run for long continuous durations like slideshows or kiosks. Having to consider the offline versus online states and a couple of other issues related to the browser platform specifically (e.g. <a href="https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Autoplay" target="_blank" rel="noopener noreferrer" class="">auto-play policy</a>) made this project a little more of a headache than I would have liked. However, maybe I'll leave that rant for another post.</p>
<p>Anyhow, see ya next time and don't forget to eat your veggies!</p>
<div style="display:flex;justify-content:center"><p><img decoding="async" loading="lazy" alt="Cat Veggies" src="https://your-docusaurus-site.example.com/assets/images/cat-veggies-64bc3e086171353e4f8e70668eeaedd1.gif" width="362" height="480" class="img_ev3q"></p></div>
<p style="text-align:center"></p><div>{ وقل ربي زدني علما }</div><p>{ and say: O lord increase me in knowledge }<!-- --> <a href="https://quran.com/20/114" target="_blank" rel="noopener noreferrer" class="">(20:114)</a></p><p></p>]]></content:encoded>
            <category>javascript</category>
            <category>frontend</category>
            <category>progressive web app</category>
        </item>
    </channel>
</rss>