Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service worker example: stops working when SW is suspended #637

Open
rejhgadellaa opened this issue Apr 5, 2023 · 9 comments
Open

Service worker example: stops working when SW is suspended #637

rejhgadellaa opened this issue Apr 5, 2023 · 9 comments

Comments

@rejhgadellaa
Copy link

I've built a simple Notification API tester web app to do some debugging on what iOS Safari 16.4 does and does not support, and figured I could use Comlink to communicate between the main thread and the service worker.

I based my code on the service worker example, but found that, on Android at least, it stops working after a while when I put the page in the background and then come back to it.

I think I found the problem: the browser is free to suspend / completely kill the SW ifi it's not in use. That means it throws away everything: the port, Comlink, bathwater, baby, tub, etcetera.

I'm not sure if there is a (good) solution that doesn't require Comlink to support Client.postMessage(), because that's the one thing that will spin up the SW?

I'm currently trying some workarounds, like checking if the SW and Comlink is still alive, etc, but I fear that needs to happen with every call:

  • I think the SW can even be killed when the page is in the foreground?
  • The SW might've been killed, spun up for some other reason - so without Comlink setup, then killed again. Even if the SW is alive, Comlink may still need to be initiated.

Will report back.

@MrMadClown
Copy link
Contributor

I don't think the SW gets cleaned up while the page is active.

You could use the visibilitychange event to check every time the user comes back to the page.

We've also implemented the Freeze/Resume Detection because our application gets suspended pretty frequently when it's not active.

@rejhgadellaa
Copy link
Author

rejhgadellaa commented Apr 5, 2023

Ah yeah I've used page-lifecycle in the past, it handles pretty much all of those cases in a streamlined event system. That said, iPadOS seems to have issues where the document loses focus when you dismiss the keyboard.

Anyway, will do some testing to make sure the SW doesn't get killed when the page is active, that would save me from a ping() (and restarting it + Comlink) for every call. Thanks!

@surma
Copy link
Collaborator

surma commented Apr 6, 2023

Yes, a ServiceWorker can definitely be killed even if the page is active. SWs are supposed to be lightweight and easily killable and respawnable. So unless you keep sending fetches or sending messages to keep it alive, it is likely that it will get cleaned up (esp. on mobile).

I don’t think Comlink is currently set up to handle a killed-and-respawned SW gracefully. That would be a cool feature in the future.

@rejhgadellaa
Copy link
Author

Yeah my testing so far confirms that (SW gets killed after 10~20 seconds, even with the page open). Not sure MessageChannel messages will keep it awake even.

I have working code that will re-init comlink but it needs some cleaning up. Still, it's a workaround. The real solution is support for postMessage and Comlink needs to use event.waitUntil( Promise ) in the Sw to prevent async operations in the SW from being killed mid-operation.

@MrMadClown
Copy link
Contributor

@surma oh! Did not know that, do you have a good article/documentation at hand?
A quick search didn't yield anything explaining service worker termination / clean up.
Maybe I didn't search thoroughly enough.

@surma
Copy link
Collaborator

surma commented Apr 6, 2023

Even event.waitUntil() allows the UA to kill the ServiceWorker if it keeps it alive for too long, because it may consider it “abnormal”.

It’s pretty well put at the start of the spec:

Screenshot 2023-04-06 at 13 25 05

@DanielGiljam
Copy link

Yeah my testing so far confirms that (SW gets killed after 10~20 seconds, even with the page open). Not sure MessageChannel messages will keep it awake even.

I have working code that will re-init comlink but it needs some cleaning up. Still, it's a workaround. The real solution is support for postMessage and Comlink needs to use event.waitUntil( Promise ) in the Sw to prevent async operations in the SW from being killed mid-operation.

Found a Chrome Developers blog post stating that MessageChannels do wake up ServiceWorkers.

https://developer.chrome.com/blog/broadcastchannel/#:~:text=//%20We%20can%27t%20use%20a%20BroadcastChannel%20for%20this%20because%20the%0A//%20service%20worker%20may%20need%20to%20be%20woken%20up.%20MessageChannels%20do%20that.

CleanShot 2023-07-09 at 14 55 14@2x

But the statement contradicts the code that's below it. I believe it's like you said, the service worker can throw away the port, Comlink, bathwater, baby, tub... 😝 What the example code in the article seems to suggest, however, is that navigator.serviceWorker.controller.postMessage() will wake up the service worker, but I guess that is kind of obvious…

Or how would you interpret that article's statement?

@DanielGiljam
Copy link

Also found this old pull request from 2020 which suggests to address this problem: #493

@daniel-nagy
Copy link

daniel-nagy commented Jan 19, 2024

@rejhgadellaa You should think of service workers like server-less functions when it comes to communication with the main thread.

I am the author of a library called Transporter that was heavily influenced by Comlink but attempts to have more real work usability. Transporter supports communication with a Service Worker using the BrowserServer API. Here is a codesandbox that shows how to use Transporter with a service worker. Note that you may need to disable certain security features in your browser for ServiceWorker to work in codesandbox, or open the preview in a top-level browsing context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants