The log said the sync was scheduled. Two minutes later, nothing had run. No error, no rejected promise, no missed callback warning — just a line that promised future work and a database that never changed.
Here is the excerpt that ended a week of blaming my own debounce logic:
[10:41:02] change detected [10:41:02] sync scheduled in 120000ms [10:41:32] service worker terminated (idle)
Enter fullscreen mode
Exit fullscreen mode
The timer did not fail. The process that owned it was shut down, and a setTimeout cannot outlive its process.
The short version
setTimeout is a handle in the worker's heap. Terminate the worker and the handle is gone.
MV3 kills an idle background worker after about 30 seconds, no matter what is pending.
Persist the due time , not the timer, and re-arm it when the worker wakes.
Three suspects that were innocent
The debounce. The code coalesced rapid changes into one sync two minutes later. It worked in tests because I kept clicking things, which kept the worker alive.…