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

Allow active worker to immediately evict itself #1296

Open
asakusuma opened this issue Mar 29, 2018 · 10 comments
Open

Allow active worker to immediately evict itself #1296

asakusuma opened this issue Mar 29, 2018 · 10 comments

Comments

@asakusuma
Copy link

There's currently no way for an active service worker to, by itself, evict itself, i.e. immediately remove itself as a controller for any client. Such a feature would be useful for implementing some sort of service worker "heartbeat" that checks against a server.

Achieving the same result with the current service worker API requires coordinating with the installing and/or waiting worker.

To solve this issue, It would be nice to have an API with the following capabilities:

  1. Evict the service worker
    1. Stop handling any new events
    2. Wait for any existing tasks to complete
    3. Remove the worker as the controller/active worker across all clients and the registration
  2. Optionally provide an “ultimatum” timeout for finishing any functional events
  3. Optionally skipWaiting so that a waiting worker activates immediately instead of waiting for all clients to close.

For instance:

self.evict({
  timeout: 10000,
  skipWaiting: true
});

Related to #614

@asakusuma
Copy link
Author

It would be nice if this API was also available from the window context. That way the window could implement the health check as well.

@asakusuma
Copy link
Author

@jakearchibald not sure whether to continue the F2F terminate discussion here or in #1292.
If we go with your suggestion of serviceWorker.terminate() / self.terminate(), this ticket might fit better.

At a high level, the API should:

  • be available from both the window and the worker context.
  • allow providing a deadline for existing tasks before hard removal
  • allow choosing between removing the entire registration or just removing the active worker (i.e. effectively skipWaiting())

@mattto any insights on how easy this would be to implement?

@jakearchibald
Copy link
Contributor

@asakusuma I'm going on the assumption that 'evict' means "any client controlled by this service worker becomes uncontrolled". What happens if these uncontrolled pages are reloaded, do they become controlled again? Can you describe a scenario where you'd call this API (I don't fully understand the heartbeat thing)?

@asakusuma
Copy link
Author

@jakearchibald

I'm going on the assumption that 'evict' means "any client controlled by this service worker becomes uncontrolled"

Sort of. The original intent of this issue is now partly covered by CSD, although I think some additional supporting features may be necessary (gonna post another issue shortly).

The use case that I believe could use work is when the active worker (or the client) expects there to be a newer version and wants to initiate a "forced/manual" activation that newer version.

For example let's say you wanted to implement feature flags in a service worker by embedding some boolean flags in the service worker script. And lets say your service worker normally doesn't use skipWaiting(). But if there's an "on" flag in a worker that you want to turn off, you want the "off" state to activate immediately. One way to implement this is to have the service worker check a heartbeat endpoint and send the current flag state. The server could use CSD when the flag state sent by the service worker is invalid, but this is a little heavy handed. Instead, I think we should allow the active worker to simply declare that the registration should either activate to the latest (if it exists) or gracefully evict the current worker until a new version is available.

@jakearchibald
Copy link
Contributor

you want the "off" state to activate immediately

We've got registration.update() and skipWaiting(). Are you saying that's too slow, so it's better to switch to an uncontrolled state in the meantime?

@asakusuma
Copy link
Author

True, but the currently active worker doesn’t have direct access to skipWaiting(). We can sort of work around this by sending a postMessage to the waiting worker, asking it to call skipWaiting, but this approach doesn’t appear to be super reliable. We ran an experiment where the control group was “always use skipWaiting”.

@jakearchibald
Copy link
Contributor

Does that mean #1016 is the solution here?

@asakusuma
Copy link
Author

The update flow is good enough the vast majority of the time, but in every experiment we’ve run, there’s always a very small subset of devices (~.01%) that have enough connectivity to beacon tracking events and hit the heartbeat server, but for whatever reason don’t actually get updated.

@asakusuma
Copy link
Author

#1016 solves part of the problem. The rest of the problem is around edge cases that we have observed empirically. I.e the server is serving a new version, update is called, but we observe that the old worker is still doing things. The update flow works 99.9% of the time. It would be nice if CSD could handle the other .1%, but it’s difficult for the server to detect that a browser is in this .1%. I have some ideas around how to potentially solve this.

@asakusuma
Copy link
Author

Somewhat related issue: there's no way to apply Clear-Site-Data if you're offline: w3c/webappsec-clear-site-data#40

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

2 participants