Running a timer each second and Keeping service worker alive and using setInterval

266 views
Skip to first unread message

Joel Benjamin

unread,
Oct 11, 2024, 2:45:39 AMOct 11
to Chromium Extensions
Hi!

I run a focus timer extension with close to 60k users. And as you know, with focus timers you deal with time. But the problem I've been facing is that timers are really hard to get right in manifest v3.

 Previously when using V2, it was pretty easy since I could just run a setInterval and the background script would do its thing because it was persistent. But in v3, since it's using Workers, it's quite difficult to persist any state and sometimes the service worker dies too.

I migrated to V3 in mid-2023, and I decided to use the chrome alarms API to create my timer. But as you know the timer isn't very accurate and it only works correctly when it's unpacked. To make the timer tick every second, I'm using the "when" argument and creating a new timer every second. This works, but it is hacky and probably consumes more resources compared to the v2 persistent workers.

I also store the countdown state every second so that in case the service worker dies, which it does many times. I can just resume the timer when the worker becomes alive again. 

Now here's my problem: 
1. My users are not happy with it because the timer is very inaccurate and stalls a lot. I personally use it, too, and it becomes really annoying, so I understand the frustration of my users. Overall, it's not a very good experience.
2. I'm using too many hacks to make it when it worked fine in v2 

I've been looking for answers on the web to make it work but there aren't many. I came across a couple of posts but not very satisfying answers or i've tried the solution before.

Then a couple of days ago I came across this from the Docs on how to keep the SW alive.


I'm quite skeptical of this solution since all it's doing is updating the state in local storage. I'm doing something similar with my timer code, which updates local storage each second, but the timer still stops (packed ext) until it's restarted again by some other logic I wrote.

And from the docs
- "We have identified enterprise and education as the biggest use cases, and we specifically allow this there, but we do not support this in general" 
- "It is not allowed in other cases and the Chrome extension team reserves the right to take action against those extensions in the future."

These lines are not very encouraging to developers. Do I consider my extension under education or not? What happens when the Chrome team decides my extension doesn't fall under education? Do I just let my extension die? 

What I'd like to know is
 - Is it recommended to use setInterval in service workers? I know it's not persistent but I have no other option because Chrome Alarms aren't very reliable. setInterval really solves my problem if only the service worker didn't die often. 
- What other solutions can I try to get my extension working smoothly

It would be very convenient for all developers to have a persistent flag like we had in v2.

I hope I've explained my problem well. Looking forward to getting a response to this.

Thank you and Have a nice day! 




kg_17

unread,
Oct 14, 2024, 11:17:44 PMOct 14
to Chromium Extensions, Joel Benjamin
The code you linked to under 'Keep a service worker alive continuously' will prevent a service worker from stopping.  An extension api call resets a service worker timer back to 30 seconds.  In that code, chrome.storage.local.set is run every 20 seconds.

However, the service worker may stop abruptly when a computer awakens from sleep in Windows when using that code.  The time sleeping effects a service worker timer in Windows (not Linux).  For example, if a service worker has 25 seconds left on its timer when a computer is put to sleep and is awakened 10 seconds later, the service worker will have 15 seconds left on its timer.  If the computer instead was in sleep mode for over 25 seconds in that case, then the service worker timer will expire immediately when the computer awakens.  If the service worker timer expires when the computer awakens, code triggered by an expired setTimeout, setInterval, or alarm will still run, but there is no guarantee an extension api call in that code will reset the service worker timer or all async code will finish running before the service worker stops.

The only reliable solution I've seen to keep a service worker from stopping is to connect it to a native application.  That's not very convenient to setup, though...

woxxom

unread,
Oct 15, 2024, 8:46:32 AMOct 15
to Chromium Extensions, kg_17, Joel Benjamin
I'd say it is wrong conceptually that service worker's idle timer is not reset to its full 30 seconds after the computer wakes up because it's counter-productive: the user will normally do something in the next seconds after waking up the device, so if the service worker dies, it'll have to be started again, which is a waste.

Oliver Dunk

unread,
Oct 15, 2024, 9:07:12 AMOct 15
to Joel Benjamin, Chromium Extensions
Hi Joel,

Could you share some more context about what work your extension needs to do each second?

For all of the reasons you mention, I can see how the approach you were using in Manifest V2 wouldn't be the right approach. I think there might be some solutions that don't necessarily require the service worker's lifetime to be manually extended, though.

Thanks,
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB


--
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/e4426512-dded-4b2c-a8f6-a1b9506b1e22n%40chromium.org.

woxxom

unread,
Oct 15, 2024, 9:14:54 AMOct 15
to Chromium Extensions, Oliver Dunk, Chromium Extensions, Joel Benjamin
It's a generic timer problem that applies to thousands of extensions. Thing is, the timers installed by a content script can be trivially cleared by the web page, so the only reliable way to use a timer is to do it inside the extension process, normally in the background script. Then it either sends a message back to the content script, which does something in the web page, or calls some `chrome` API e.g. animates the icon or changes the badge once a second or displays a notification or downloads something or does thousands of other things.

Oliver Dunk

unread,
Oct 15, 2024, 9:17:50 AMOct 15
to woxxom, Chromium Extensions, Joel Benjamin
As you mentioned, there are lots of different things that a timer might do.

The guidance for an extension that wants to update the badge every second is going to be very different to one which wants to trigger a download.

Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

woxxom

unread,
Oct 15, 2024, 9:22:37 AMOct 15
to Chromium Extensions, Oliver Dunk, Chromium Extensions, Joel Benjamin, woxxom
Doing something every second or so is a super major use case used by lots of extensions, but ManifestV3 currently doesn't provide any adequate solutions, the only workaround is deprecated and discouraged right in the documentation.

There's also throttling of timers in backgrounded tabs for web pages, which also applies to content scripts, so the only way to do something with a backgrounded tab is to use a timer in the extension's background script.

woxxom

unread,
Oct 15, 2024, 9:30:40 AMOct 15
to Chromium Extensions, woxxom, Oliver Dunk, Chromium Extensions, Joel Benjamin
FWIW, if an extension doesn't need access to `chrome` API other than messaging it would be simpler to just use chrome.offscreen API document for timers with a chrome.runtime.onMessage listener and a different one (chrome.runtime.onConnect) in the background script to avoid spinning it up unnecessarily.

Joel Benjamin

unread,
Oct 15, 2024, 9:40:16 AMOct 15
to Chromium Extensions, woxxom, Oliver Dunk, Chromium Extensions, Joel Benjamin
> Could you share some more context about what work your extension needs to do each second?

My extension is a focus timer, users can set a duration and during this time, the timer counts down to zero. While this is happening in the background, the service worker must update the badge and UI each second. It is a pretty important part of the user experience. I've seen other extensions not do the countdown and instead just show the minute like "5" instead of "5:00".

When there's a lot of stuff happening, especially when many tabs are open the alarms can significantly slow down and give inaccurate time. Sometimes it even kills the service worker, and my extension has to restart the timer from where it was left off. This is where storing the timer countdown in the local storage comes in handy. I'd ideally not store it each second because it is an overkill but I have no choice.

> I think there might be some solutions that don't necessarily require the service worker's lifetime to be manually extended, though.

Well, I don't think there are any straightforward solutions. Manifest V2 was the easiest because the worker persisted therefore needing no saves. 

I was also using the timer for another critical feature called autoblock. This feature would show a countdown timer on the website and then block it. The problem was, when a focus timer and autoblock ran together, both timers would just stop. I don't know what's happening but I assume that chrome alarms can't handle a lot of timers being created at the same time.

So I had to move the autoblock logic to run in the content script, but this made syncing difficult across tabs with the same domain. It would have been easier to do it in the background script because then I could track all running timers and manage a pool of them. But this autoblock feature works now so it's not a huge problem anymore.

Oliver Dunk

unread,
Oct 15, 2024, 10:55:32 AMOct 15
to Joel Benjamin, Chromium Extensions, woxxom
Thanks! That's really helpful.

I'll try to address each of your points in turn to make sure I don't miss anything...

While this is happening in the background, the service worker must update the badge and UI each second.

Got it. In that case, calling `action.setBadgeText` each second is intended to keep the service worker alive in itself. You shouldn't need to do any additional work.

If you're not seeing this, it would be great if you could share a reproduction. Other than the few cases mentioned in this thread, if that isn't working, it sounds like a possible bug we would want to fix.

I'm quite skeptical of this solution since all it's doing is updating the state in local storage.

The solution there is accurate and should work. Other than a few exceptions (listed here), any extension API call will extend the service worker lifetime. I will note however that it isn't any different to calling setBadgeText() each second, so is unlikely to prevent any issues you're already having.

These lines are not very encouraging to developers. Do I consider my extension under education or not?

The only case where we may take action is an extension that keeps the service worker alive continuously without a clear need. For the use case here, I wouldn't expect you to have any issues.

Is it recommended to use setInterval in service workers?

Using setInterval is completely fine. Just bear in mind that the setInterval itself won't keep the service worker alive.

What other solutions can I try to get my extension working smoothly

It sounds like the best solution here would be if you could have an alarm in a packed extension that fires every second. This is actually something we're looking into. I can't promise that it will happen, but we are going to consider making that change in a future version of Chrome.

I realise there's a lot here, so please don't hesitate to ask if you have any more questions. We're happy to help :)
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

Oliver Dunk

unread,
Oct 15, 2024, 10:56:12 AMOct 15
to Joel Benjamin, Chromium Extensions, woxxom
Apologies, I shared the wrong link to the list of exceptions. You can find those here: https://crbug.com/40268762
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

Reply all
Reply to author
Forward
0 new messages