Re: [w3c/ServiceWorker] Should the worker be removed from the registration *before* its state is set to "redundant"? (#1273)

Some research on what the spec says vs what browsers do:

# One worker, going through the steps

When I say "reg: null, null, worker" I mean, on the registration, installing was null, waiting was null, active was a worker:

|      | on register resolve()   | updatefound after resolve    | on "installed"          | on "activating"         | on "activated"          |
|------|-------------------------|------------------------------|-------------------------|-------------------------|-------------------------|
| Spec | reg: worker, null, null | Yes. reg: worker, null, null | reg: null, worker, null | reg: null, null, worker | reg: null, null, worker |

Chrome, Firefox and Safari all behave the same.

# An new active worker

This is where things are different. I'm going to compare:

* Current spec
* #1416 - this is my ideal, which tries to make all related object changes before firing events.
* #1436 - a much smaller change that updates registration objects before firing

In this test, worker1 is active, worker2 is waiting. worker2 becomes active, worker1 becomes redundant.

|         | Event order           | when worker1 "redundant"                        | when worker2 "activating"                    |
|---------|-----------------------|-------------------------------------------------|----------------------------------------------|
| Spec    | redundant, activating | worker2 "installed" <br/>reg: null, worker2, worker1 | worker1 "redundant" <br/>reg: null, null, worker2 |
| #1416   | redundant, activating | worker2 "activating" <br/>reg: null, null, worker2   | worker1 "redundant" <br/>reg: null, null, worker2 |
| #1436   | redundant, activating | worker2 "installed" <br/>reg: null, null, worker2    | worker1 "redundant" <br/>reg: null, null, worker2 |
| Chrome  | redundant, activating | worker2 "installed" <br/>reg: null, worker2, worker1 | worker1 "redundant" <br/>reg: null, null, worker2 |
| Safari  | redundant, activating | worker2 "installed" <br/>reg: null, worker2, worker1 | worker1 "redundant" <br/>reg: null, null, worker2 |
| Firefox | activating, redundant | worker2 "activating" <br/>reg: null, null, worker2   | worker1 "redundant" <br/>reg: null, null, worker2 |

Chrome and Safari match the current spec, but that means a redundant worker is seen within the registration.

Firefox gets the order wrong.

# A new waiting worker

In this test, worker1 is active, worker2 is waiting, worker3 is installing. Then, worker3 becomes waiting, worker 2 becomes redundant.

|         | Event order           | when worker2 "redundant"                            | when worker3 "installed"                        |
|---------|-----------------------|-----------------------------------------------------|-------------------------------------------------|
| Spec    | redundant, installed  | worker3 "installing" <br/>reg: worker3, worker2, worker1 | worker2 "redundant" <br/>reg: null, worker3, worker1 |
| #1416   | redundant, installed  | worker3 "installed" <br/>reg: null, worker3, worker1     | worker2 "redundant" <br/>reg: null, worker3, worker1 |
| #1436   | redundant, installed  | worker3 "installing" <br/>reg: null, worker3, worker1    | worker2 "redundant" <br/>reg: null, worker3, worker1 |
| Chrome  | redundant, installed  | worker3 "installing" <br/>reg: worker3, worker2, worker1 | worker2 "redundant" <br/>reg: null, worker3, worker1 |
| Safari  | redundant, installed  | worker3 "installing" <br/>reg: worker3, worker2, worker1 | worker2 "redundant" <br/>reg: null, worker3, worker1 |
| Firefox | activating, redundant | worker2 "installed" <br/>reg: null, worker3, worker1     | worker2 "redundant" <br/>reg: null, worker3, worker1 |

The story is the same as above.

# Clear registration

In this test, worker1 is active, worker2 is waiting. The registration is unregistered.

|         | Redundancy order | when worker2 "redundant"                                            | when worker1 "redundant"                                         |
|---------|------------------|---------------------------------------------------------------------|------------------------------------------------------------------|
| Spec    | worker2, worker1 | worker1 "activated" <br/>worker2 "redundant" <br/>reg: null, worker2, worker1 | worker1 "redundant" <br/>worker2 "redundant" <br/>reg: null, null, worker1 |
| #1416   | worker2, worker1 | worker1 "redundant" <br/>worker2 "redundant" <br/>reg: null, null, null       | worker1 "redundant" <br/>worker2 "redundant" <br/>reg: null, null, null    |
| #1436   | worker2, worker1 | worker1 "activated" <br/>worker2 "redundant" <br/>reg: null, null, null       | worker1 "redundant" <br/>worker2 "redundant" <br/>reg: null, null, null    |
| Chrome  | worker2, worker1 | worker1 "activated" <br/>worker2 "redundant" <br/>reg: null, null, null       | worker1 "redundant" <br/>worker2 "redundant" <br/>reg: null, null, null    |
| Safari  | worker2, worker1 | worker1 "activated" <br/>worker2 "redundant" <br/>reg: null, null, null       | worker1 "redundant" <br/>worker2 "redundant" <br/>reg: null, null, null    |
| Firefox | worker2, worker1 | worker1 "redundant" <br/>worker2 "redundant" <br/>reg: null, null, null       | worker1 "redundant" <br/>worker2 "redundant" <br/>reg: null, null, null    |

Here the browsers break from the spec (I think they're following a test) and update the registration before firing any statechange events. Firefox goes further and updates both workers before firing any events.

I think our options are:

* Spec what Chrome and Safari are doing.
    * In some cases the registration will be updated before the statechange events fire, sometimes they won't.
    * Within a transaction, 'statechange' happens on the youngest worker first.
    * Within a transaction, worker.state is updated just before that worker's 'statechange' (meaning other workers will be showing old values)
* #1436
    * For a transaction, update the registration before firing any 'statechange' events.
    * Within a transaction, 'statechange' happens on the youngest worker first.
    * Within a transaction, worker.state is updated just before that worker's 'statechange' (meaning other workers will be showing old values).
* #1416
    * For a transaction, update the registration before firing any 'statechange' events.
    * For a transaction, update all worker.state properties before firing any 'statechange' events.
    * Within a transaction, 'statechange' happens on the youngest worker first.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/ServiceWorker/issues/1273#issuecomment-502135609

Received on Friday, 14 June 2019 14:41:57 UTC