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

Using BroadcastChannel to wake up a service worker #975

Closed
mkruisselbrink opened this issue Sep 8, 2016 · 26 comments
Closed

Using BroadcastChannel to wake up a service worker #975

mkruisselbrink opened this issue Sep 8, 2016 · 26 comments

Comments

@mkruisselbrink
Copy link
Collaborator

While a service worker can currently subscribe to a BroadcastChannel to receive messages from it, it will only receive messages as long as some other event keeps the service worker alive. It would be useful if it was possible for a BroadcastChannel to wake up a service worker.

Maybe something like this:

// sw.js
registration.subscribeToBroadcastChannel('foo');

addEventListener('onbroadcastchannelmessage', e => {
  console.log('Received message from channel: ' + e.source.name);
});

Not sure what the API should look like though:

  • Attach channel subscriptions to the registration or to the specific worker?
  • If attached to the worker, specify fixed list of subscriptions once (on install event), or allow subscribing/unsubscribing later?
  • Reuse existing onmessage event, or add new event (and if new event, what/where)?
  • Events should probably be ExtendableMessagEvent. But how will the event handler know what channel a message was send over? Could set .source to a BroadcastChannel instance, but will that instance then also get all messages to the channel?

Or rather than inventing new API surface and events, we could just record all channels the SW subscribed to after first-run similar to how we record all the events the SW subscribed to. Then we'd rely on the SW script re-subscribing to the same channels whenever it is woken up. So the following would "just work":

// sw.js
const channel = new BroadcastChannel('foo');
channel.onmessage = e => { console.log('Received message', e.data); };

// or even
new BroadcastChannel('foo').onmessage = e => console.log(e.data);

In some sense not having extra API seems cleaner, but it's also kind of magic, and we'd have to decide when to record what channels the worker is actually subscribed to... Thoughts?

@mfalken
Copy link
Member

mfalken commented Sep 9, 2016

@annevk
Copy link
Member

annevk commented Sep 9, 2016

I think we should have an opt-in API.

@annevk
Copy link
Member

annevk commented Sep 9, 2016

To clarify, invoking the constructer having side effects like that is somewhat frowned upon.

@wanderview
Copy link
Member

It would be nice if we could make all "message event delivering" APIs just "do the right thing" in regards to service workers. Both start the SW if necessary and fire an ExtendableMessageEvent.

@jakearchibald
Copy link
Contributor

Do we have any use-cases in mind here? I'm not sure we need this.

Say I have an installing, waiting and active worker, which would receive the broadcast?

@wanderview
Copy link
Member

Do we have any use-cases in mind here? I'm not sure we need this.

Maybe not. I was thinking of the multi-instance stuff we were talking about. But that does not require waking the worker.

Possibly we don't want ExtendableMessageEvent either since it would let a worker broadcast to itself, get a new waitUntil, and defeat the shutdown timers.

@asutherland
Copy link

It seems like any choice here would want to be consistent with the behavior of MessageChannel/MessagePort. Given the ramifications of the spec for those either trying very hard to avoid making garbage collection visible or eliminate the foot-gun of not holding a strong reference to the MessagePort, I worry that this gets messy quickly and encourages falling into the trap of using a ServiceWorker like it's a SharedWorker. And at the July F2F I felt like there was agreement that explicit SharedWorkers were far better than never-dying ServiceWorkers, even if some engines need to add them (back).

I could see it being reasonable in the FAQ to have:

  • Q: How do I use ServiceWorkers with BroadcastChannels/MessageChannels?
  • A: You want to use a SharedWorker. ServiceWorkers only live long enough to service the ExtendableEvents dispatched to them and then may be terminated. Your long-lived SharedWorker can interact with the short-lived ServiceWorker as needed. In exceptional cases, it may make sense to instantiate a MessageChannel for the duration of an ExtendableEvent, but keep in mind that events will eventually be terminated if they take too long. If your processing may take an unbounded amount of wall-clock time, you will want to move as much of it as possible into the SharedWorker and potentially issue multiple requests to the ServiceWorker.

@annevk
Copy link
Member

annevk commented Sep 9, 2016

@asutherland if all vendors are agreed that shared workers should stay, you might want to communicate that at whatwg/html#315. I believe we're adding telemetry for them in Gecko…

@asutherland
Copy link

@annevk My memory is that:

  • The Apple attendees indicated that Safari removed SharedWorkers and no one complained.
  • The Apple attendees were very interested in being able to implement ServiceWorkers so that every ExtendableEvent effectively got its own fresh global.
  • The Apple attendees thought bringing SharedWorker back would be worth it if it allowed the fresh global approach to work.

Since the F2F it's become less clear that the fresh-global/multiple-instances strategy is viable or is going to become viable, so I don't think we can report the above as unconditional support for SharedWorkers.

@jakearchibald
Copy link
Contributor

I really like BroadcastChannel, but I don't think it's useful to make it service-worker-waking.

I can imagine my installing worker using it to broadcast progress updates to pages that are displaying install UI, but that works with the current API.

@nolanlawson
Copy link
Member

Same, I'm not sure what you can do with BroadcastChannel waking up a SW from a page that you can't already do with Web/Shared Workers.

@annevk
Copy link
Member

annevk commented Sep 26, 2016

@nolanlawson is Microsoft implementing shared workers?

@nolanlawson
Copy link
Member

We have no immediate plans, no. 😉 Just pointing out that these kind of use cases are arguably already covered in other specs.

@annevk
Copy link
Member

annevk commented Sep 27, 2016

Fair, but we might end up removing them if nobody else implements them and at that point we can't really consider them as alternatives anymore.

@rektide
Copy link

rektide commented Nov 23, 2016

Use case:

My multi-tab application includes a music player widget, that needs to get updated on every instance, & which needs to load (in an appropriate state) when a new tab of it is opened. I'd like to send the player state out via Broadcast Channel. If the SW can listen to the Broadcast Channel, it can update it's cache based on these events.

This seems like a somewhat vital capability for integrating Service Workers with Event Source architectures.

@rektide
Copy link

rektide commented Nov 23, 2016

For implementation, perhaps a new addEventListener param for SW consumers to signal their desire to be woken up:

var bc= new BroadcastChannel("test_channel")
bc.addEventListener("message", ()=>console.log, {persistent: true})

This gets around objections of side-effects from constructor parameters.

@wanderview
Copy link
Member

@rektide Can't you use a SharedWorker for this? It can listen for BroadcastChannel events and use Cache API.

@jakearchibald
Copy link
Contributor

Closing this due to lack of interest, but we can look again if interest picks up.

@stroobandt
Copy link

Same, I'm not sure what you can do with BroadcastChannel waking up a SW from a page that you can't already do with Web/Shared Workers.

Showing a notification upon a received broadcast message is the issue I bumped into today...
So yes, five years later, this still looks an interesting feature to have.

@Iconejey
Copy link

Iconejey commented Jul 7, 2021

Showing a notification upon a received broadcast message is the issue I bumped into today...
So yes, five years later, this still looks an interesting feature to have.

Same here, I need users to be able to send reports (including pictures of their work) from their phone to the server, but still allow them to quit the app to keep working while the service worker waits for server connection to send the data. The client sends the report via a boardcast channel to the SW which will show a progress notification. The problem is the lack of ExtendableEvent.waitUntil() makes the SW stop in the middle of the tranfert...

Are basic Workers or SharedWorkers better for this kind of use?

@stroobandt
Copy link

@Iconejey Basic web workers can wake up a service worker to give out a notification.
This works for an indefinite amount of time with PWAs running in desktop browsers.
However, a basic web worker running in Chrome on an Android device will itself be put asleep after about 5 minutes. So, all will be in vain if larger notification intervals are required.
Here, you can read more about my attempts and grievances with notifications.

@jakearchibald
Copy link
Contributor

@Iconejey

I need users to be able to send reports (including pictures of their work) from their phone to the server, but still allow them to quit the app to keep working while the service worker waits for server connection to send the data

Doesn't https://developers.google.com/web/updates/2015/12/background-sync do this?

@blackmambahk
Copy link

We are using Server Sent Events to notify web clients that some server side action has been triggered on tasks they are interested in whilst they have the SPA open.

Typically a User is assigned to multiple projects and they tend to have multiple tabs open with various application screens (SPA). There maybe changes to those projects that happen elsewhere whilst they have the app open and we notify which projects changed and then carry out client side actions depending on the change.

The active ServiceWorker part of this is very short lived, a message is received by the ServiceWorker it then notifies all attached WindowClients of the event and then it's done.

We initially implemented this in the browser using a ServiceWorker which was easy to implement but we were hit by the issue of the SW going to sleep and not reawakening on an SSE event, we were unable to find any way to reliably keep the SW 'alive'.

We then switched these to SharedWorkers as we can keep them alive and that works but the issue here is they are not implemented on Chrome Android.

So whilst it may be fair to say anything you can do with waking up a ServiceWorker can be done with a SharedWorker already, SharedWorkers are not available everywhere and it's not just Safari that hasn't implemented them.

So waking up a ServiceWorker on a MessageEvent would still be very useful.

@Iconejey
Copy link

@jakearchibald

Doesn't https://developers.google.com/web/updates/2015/12/background-sync do this?

Background-sync only triggers an event "out of nowhere" so the data I need to send would not be accessible unless I use something like localStorage, which has a limit in storage capacity (5-10MB depending on browser).

The reports I need to send often reach up to 30-40MB, which is the main reason I want the upload to be in the background. It may take a while to upload this much data.

@wanderview
Copy link
Member

@blackmambahk FYI, you can star this chromium bug for shared worker support on android to get updates and to demonstrate a desire to see it fixed: crbug.com/154571

@blackmambahk
Copy link

@blackmambahk FYI, you can star this chromium bug for shared worker support on android to get updates and to demonstrate a desire to see it fixed: crbug.com/154571

Yes I know, I had done that already.

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

No branches or pull requests