-
Notifications
You must be signed in to change notification settings - Fork 313
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
skipWaiting() promise should resolve after promotion to .active #1187
Comments
Yeah, I agree that addEventListener('install', () => event.waitUntil(skipWaiting())); …which would create a deadlock with the changes you mention. Related: #1016 |
Ah I see, I also discovered #1015 too I guess we'll implemented as spec'd but it's pretty weird. An implementation that always resolves the promise immediately wouldn't be super wrong, it can plausibly claim that the active version just happened to be handling an event at the exact moment you called skipWaiting(). If we were to design it over, would we give skipWaiting a promise? Is there any use case for using the promise? I'm wondering if developers are using the promise expecting it to mean something it doesn't. |
Heads-up that I think the current WPT test for this is wrong. Would be great if @wanderview @jakearchibald @jungkees can confirm my analysis. The current test skip-waiting-installed.https.html[1] sets up a waiting worker and an active worker with a client. The worker calls skipWaiting() and then checks that the promise resolves before the 'activate' event handler runs. But tracing through the spec, skipWaiting() enters "Try Activate". "Try Activate" invokes "Activate". "Activate" blocks until the final step: "Update Worker State" queues a task to set ServiceWorker#state to 'activated'. That means skipWaiting's promise resolves before that task runs. But back in step 10, we have dispatched the 'activate' event. Therefore the order should be:
We're planning to change the test to assert that order. For more context, this came up in https://chromium-review.googlesource.com/c/chromium/src/+/599570, Xiaofeng Zhang believes the spec changed in #1065 so that the test is now wrong. [1] |
FYI: we're revising the test at https://chromium-review.googlesource.com/c/chromium/src/+/646244 |
I think a series of spec changes have changed skipWaiting() indirectly. I agree the current spec says that skipWaiting() should resolve before the worker state is updated, but is that the intent of this promise? Should we instead change the skipWaiting() spec to effectively listen for a statechange event and resolve then? @jakearchibald @jungkees what do you think? |
In any case, we'll update the test to match the current spec, and whenever the spec changes we can update the test again. |
As commented in #1015 (comment), that change may create a deadlock to install handlers that waitiUntil the given skipWaiting promise. It seems we should keep the current behavior to not break the existing code. It should have been better if it returned void. |
I think we can just add "Wait for all the tasks queued by Update Worker State invoked in this algorithm to have executed." to after Step 15 of Activate. There's similar verbiage elsewhere and I think it matches the intent of the algorithm as wanderview asks in #1187 (comment). So this way, in the common case, the order will be:
(so 2 and 3 are flipped from #1187 (comment)) |
The Activate algorithm's final step was to run Update Worker State to make the worker `activated`. However Update Worker State just queues a task to do so. So the task would run after skipWaiting() resolved its promise, which wasn't the intent of the spec. Fixes w3c#1187.
@mattto I can't figure out how that fixes the deadlock in #1187 (comment). Step 1 would be blocked by step 3. |
If we think #1187 (comment) is no longer a problem (do we have data?), then it feels like |
Resolving it once the service worker moves from |
This change shouldn't regress the current spec: if it didn't deadlock before, it wouldn't deadlock now. If one does This change only affects the case where I'm motivated to fix this because we would need to add some complexity to Chrome to guarantee the order per the current spec. I suspect sites would still deadlock if the spec didn't guard against it, e.g., with the Try Activate escape hatch. Another alternative is to just have |
@mattto, I left the above comment before I saw your last comment.
You're right. I missed this point indeed. I'll review your PR. @jakearchibald, @wanderview, given @mattto's analysis, calling |
@mattto, I just looked into #1327. Wouldn't it be nice if we could do #1187 (comment)? |
I dunno, I'm wondering now why we don't just resolve immediately always. It would be simple and no deadlock. |
As we made it a promise (not returning void), just guaranteeing the state transition - from installed to activating seems like a better behavior if we could do (under the premise that it won't deadlock). |
As noted in the original post, we resolve immediately in other cases too. AFAICT there is a rather limited case where we try to resolve it to something meaningful. It only happens when the service worker is already installed AND the active worker has no events AND something asks the installed worker to call skipWaiting(). Changing the meaning of the promise that much seems to add complexity for little gain. |
Sorry about the confusion, but please ignore my comments from #1187 (comment).
There's a case when registrations can hold an waiting worker while installing a new one. |
We already have a deadlock scenario:
Should we make it "just resolve immediately always" as @mattto suggested? |
As spec'd the skipWaiting() promise doesn't seem really useful. I think it might be an oversight.
I'd expect the promise to resolve after the worker has been promoted to .active and has state 'activating'.
But currently the spec is:
2. Invoke Try Activate with service worker's containing service worker registration.
3. Resolve promise with undefined.
And Try Activate early returns in some cases:
So if Try Activate early returned, we resolve the promise before activating.
Also am I parsing this sentence correctly: "The result of running Service Worker Has No Pending Events with registration’s active worker is true, and no service worker client is using registration or registration’s waiting worker's skip waiting flag is set." means "A && (B || C)" where A = "no pending events", B = "no client" and C = "skip waiting flag".
The text was updated successfully, but these errors were encountered: