[whatwg] Combining the DedicatedWorker and SharedWorker interfaces

Alexey Proskuryakov wrote:
>
> Nov 6, 2008, ? 2:18 AM, Jonas Sicking ???????(?):
>
>>> Similarly, having separate interfaces for Worker and SharedWorker
>>> implies that there is some fundamental difference in their behavior -
>>> a difference that eludes me so far.
>>
>> A shared worker is shared between all scripts on a single site[*] that
>> instantiates a worker with the same name. I.e. where the second
>> argument to the constructor is the same. (Don't remember what happens
>> if the second argument is the same as an existing worker, but the
>> first is not, check with the spec).
>
> Sure, that part is clear - but it's only about the behavior of the
> object's constructor, not the object itself! It alone doesn't warrant
> having a separate interface.
>
> As an example from another area, see mmap(2) function - you can pass
> MAP_ANON or MAP_FILE via its flags to achieve similar results. Note also
> that it has a number of other options. If we create a separate interface
> for every Worker isolation level needed (both inside and outside), we'll
> soon end up with PrivateWorker, SharedDataWorker and who knows what else.

So at this point the main problem with making any changes is that we
are very close to shipping Firefox 3.1. I.e. it is extremely hard to
make changes. It is very unfortunate that we have ended up in this
situation again. We were in a very similar to the window.postMessage
API where we had to scramble last minute to make changes, the result
that time was that security issues in the API slipped by since those
changes happened after we had done our security review of the spec.

A few months ago representatives from google, apple, and mozilla met
to try to agree to an API. We came up with a few guidelines, such as
that it was ok to have a separate API for shared and dedicated workers
as well as others that I don't specifically remember. At the end of
the meeting we had a rough sketch of an API. A few days after that
Hixie published a proposal. At mozilla we were largely fine with the
proposal modulo some details that we commented on fairly quickly and
then proceeded to implement.

Now, months later, both google and apple is asking for some pretty
significant changes, including reverting things like separate APIs for
shared and dedicated workers. It is very close to release for us and
we are already in a very frozen state, so making changes at this point
is somewhere between risky and impossible.

If we really want to make changes to the spec, we better make them
really fast, ideally within a day or two. And depending on the
complexity of the changes we might still be able to do them. The other
alternative is of course removing workers from FF 3.1 and waiting
until next release (judging by past releases, somewhere between a year
or two from now). Finally, we can simply stick with the current API,
none of the complains about the current syntax seems to have been very
catastrophic, such as "doesn't satisfy use cases", "hard to
understand", "easy to have hard-to-discover bugs", etc. They mostly
seem to be syntactic and the case of the matter is as always that
there is no perfect syntax as the problem is over constrained.

I see lots of ideas floating around but many of them are severly
lacking in detail so it's hard to comment on. Things like 'rename
startConversation to connect' is very ambiguous as has shown by recent
discussions. So what follows is an effort to try to focus in on some
discussed changes more concretely:

The main two things that people seem to dislike in the current are
1. The many communication mechanisms.
2. Different APIs for shared and dedicated workers.

I've said before that I don't really think 1 is true. There is
currently one communication mechanism (postMessage/onmessage) and one
connection mechanism (onconnect). There is also one convenience
function on top of the communication mechanism (startConversaion), but
is a stretch to call it a separate communication mechanism. The
communication mechanism (postMessage/onmessage) does come in two
flavors though as you for shared workers and dedicated workers call
the functions on different objects.

2 I think is as much of a feature as a bug. Dedicated workers are by
nature simpler since there is a one-to-one relationship between
browsing context and worker rather than a many-to-one. So by having
different APIs we can allow the dedicated worker API to be simpler.
That said, I do agree that it is unfortunate that the mechanisms are
different.


So, here are some concrete proposals for a few changes we can make,
and comments i've heard/made about them. The changes refer to the
*current draft*, so please check the behavior defined there.

* Remove startConversation
Details:
Simply remove the startConversaion function on all interfaces where it
is defined. Since it doesn't define any new events no other changes
are needed.

Comments:
There seemed to be opinions before on that it should definitely be
removed, however it sounds like that is less the case now. I don't
really care about this one. startConversation is just a convenience
function on top of postMessage anyway. If there still is any
disagreement about its neccessity or the fact that it adds to that we
have too many communication mechanisms i'd prefer we remove it for now
and then discuss it once we've agreed on the rest of the API, or we
can let it be for this version of the spec. Others have commented that
startConversation is a red herring in these discussions, I agree.
 (This would be no problem for us since we don't implement
startConversation yet).

* Make the external API for shared workers that of the current dedicated worker
Details:
Move the postMessage/onmessage functions from the SharedWorker.port
object to the SharedWorker object. The SharedWorker would act as a
MessagePort that is entangled with the port that is provided to the
SharedWorkerGlobalScope through already specified 'connect' event that
is fired when a SharedWorker is created.

Comments:
The result of this would be that on the outside shared workers and
dedicated workers have exactly the same API to the outside world,
except that dedicated workers have a terminate() function (formerly
known as close(), changed in the latest version of the spec).
I think this is a good idea all around and we should make this change.
(This would be no problem for us since we don't implement shared
workers yet).
Hixie expressed some dislike about the fact that we'd end up with
MessagePort entangled with something that isn't a MessagePort. This
can result in uglyness if the MessagePort is passed out outside the
SharedWorker, and then passed on anywhere. A page could create a setup
where calling postMessage on a SharedWorker object actually resulted
in onmessage being called inside another window rather than inside a
worker global scope.
I don't really think this is a big deal though, you have a very
similar situation today where calling postMessage on a
SharedWorker.port object can do exactly the same thing.

* Make dedicated workers receive a 'connect' event when they are created
Details:
Make the internal communication API for a dedicated worker exactly
that of what a shared worker is currently specced as. This means
 - Once a dedicated worker is instantiated automatically fire a
'connect' event which contains a MessagePort object (accessible
through event.port).
 - Make the Worker object entangled with this MessagePort.
 - Remove the postMessage/onmessage functions from DedicatedWorkerGlobalScope

Comments:
I don't feel super strongly about this. From a purely dedicated worker
perspective this doesn't really add any value but rather just
complexity. Everyone using dedicated workers will have to set up a
dummy function that just listens for a 'connect' event and sets a
global port variable. The upside is that combined with the above
change it makes the API for dedicated and shared workers exactly the
same.
We are currently looking in to if this is doable without adding too
much risk to FF3.1. The big concern here is more objects means more
chances of leak bugs since we can't reuse the same leak prevention
mechanisms as we do on the main thread since that one isn't
threadsafe. Anyhow, it's an implementation detail, but it is a big
part of why making even small at this stage is non-trivial.

* Add a connect() method to Worker and/or SharedWorker
There has been lots of talk about this, but I'm still confused as to
what the exact proposals are due to lack of details. But here is my
interpretation
Details:
 - Make instantiating a SharedWorker *not* fire a 'connect' event automatically.
 - Remove the .port property from SharedWorker
 - Remove the postMessage/onmessage functions from Worker and
DedicatedWorkerGlobalScope
 - Add a onconnect property on WorkerGlobalScope
 - Add a connect() method on AbstractWorker. The function fires a
'connect' even on the WorkerGlobalScope, the event has a .port
property which is a MessagePort. This MessagePort is entangled with
another MessagePort which is the value from the connect() function.

Comments:
Compared to just doing the other above proposals I think this adds
needless complexion for value that I don't quite see. If you want to
have several 'conversations', I.e. several separate MessagePorts, with
a dedicated worker you can use postMessage and |new MessageChannel|
(or the startConversation shorthand) to accomplish that. If you want
several conversations with a dedicated worker you can do the same
thing, or even call |new SharedWorker| multiple times.


Ok, I hope I've covered all angles. Again, if we really need to make
changes that require changes to FF3.1 we need to make them fast and
keep them scoped if we are going to have any chance of making it.

/ Jonas

Received on Thursday, 13 November 2008 02:12:19 UTC