[whatwg] Persistent SharedWorkers

My team at Google is experimenting with supporting persistent SharedWorkers
(SharedWorkers whose lifetime is not linked to being entangled with an
active browser window). I've reviewed some of the mailing list archives, so
I'm aware of at least some of the past discussions on this topic - I wanted
to give everyone a braindump of some of the ideas/issues we're kicking
around and get some feedback from the community at large before going
forward.

- Motivation:
There are a number of use cases where a web application would like to
provide long-running services for the user that do not go away when the user
closes his browser window. A canonical example of this is calendar
notifications - a calendar application might like to have a persistent
worker that monitors the user's calendar events, and displays notifications
to the user when he has a meeting. Likewise, a user might want his mail
application to display an unobtrusive notification when new mail arrives at
the server. These are all use cases that native applications have supported
for years, but which web-based applications currently have no way to
achieve.

- Persistent worker lifetime:
A persistent worker would never be shutdown by the "closing orphan workers"
mechanism, although it could still be killed by the User Agent (infinite
loop protection, explicit user management, revocation of permissions) or by
the worker explicitly invoking WorkerGlobalScope.close(). Once a persistent
worker is created, it would be started up on every subsequent invocation of
the user agent until it has been killed. The intent is that user agents that
have registered persistent workers would launch on startup (i.e. launch when
the user logs in to his OS account) to allow persistent workers to always
run as long as the user is logged into the machine, although this is not
required behavior.
- Permissions:
Installing a persistent worker is essentially giving a web application a
near-permanent footprint on your PC - we need explicit permission from the
user, and we need some mechanism in the user agent to revoke this
permission. There are a number of examples of similar permission-granting
user flows (ActiveX installation, plugin install, gears) which we could use
as a model for our "grant/revoke permission" UI.

The idea is that when an application instantiates a persistent worker for
the first time, the user would be prompted to grant permission (the worker
thread would not be started until the user granted permission) - in the case
that the user does not grant permission, the parent page would have its
worker.onerror() handler invoked. Revoking permission would happen on a
per-domain basis and would kill all persistent workers for that domain via
the existing kill worker mechanism described in the WebWorkers spec.

We're not certain whether we need to expose APIs to allow a client to test
whether permission has been granted or not (for example, a web application
may want to interact with a persistent worker if it exists, but there isn't
currently any way to tell if a worker exists or not without instantiating a
worker, which might prompt the user for permissions). Gears had an explicit
permissions variable applications could check, which seems valuable - do we
do anything similar elsewhere in HTML5 that we could use as a model here?

- Changes to worker APIs:
The existing SharedWorker APIs should be sufficient for interacting with the
worker - SharedWorkers can already precede/outlive individual browser window
instances, so from the standpoint of a given Window they should operate
similarly.

An application can create a persistent worker via the PersistentWorker()
constructor:

    var worker = new PersistentWorker('worker.js', 'core');

The namespace for PersistentWorkers are identical to those of SharedWorkers
- for example, if you already have a PersistentWorker named 'core' under a
domain and a window tries to create a SharedWorker named 'core', a security
exception will be thrown, just as if a different URL had been specified for
two identically-named SharedWorkers.

>From an entangled Window's standpoint, the persistent workers appear
identical to SharedWorkers - they implement the SharedWorker interface and
so expose identical APIs.

- Worker UI:
>From the worker standpoint, the main difference between a PersistentWorker
and other types of workers is that the normal way of interacting with the
user (via an open browser window) is not available, since there may be no
windows open to the parent domain. We have yet to enumerate through all of
the use cases, but our initial brainstorming came up with a few possible
types of desired interactions:
1) Display an icon in the OS status bar. This would be an unobtrusive way
for a given domain to display things like "you have new mail" or even errors
like "unable to contact server". If supplied with an onclick handler, this
could also be the footprint for further types of user interaction:

2) Open a browser window to a specific URL. I can imagine that popup
blockers might block these windows except in response to a user action (like
a click on the status bar icon).

 3) Toast (http://en.wikipedia.org/wiki/Toast_(computing)<http://en.wikipedia.org/wiki/Toast_%28computing%29>)
- behavior is similar to the showNotification() API that was previously in
HTML5.

To enable these interactions, we'd add something like the following new APIs
to the global scope for persistent workers:

void open(url, optional target, optional feature, optional replace) - opens
a browser window, just like the window.open() API which is available from
page context

showNotification(url) - displays the HTML at the passed URL to the user via
a toast popup. user agents may put restrictions on the size of the resulting
window. The original HTML5 showNotification() API was much more limited (a
few lines of unstyled text, an icon, and an onclick handler) - Dmitry Titov
makes the case for full-HTML notifications here:
http://docs.google.com/Doc?id=dhg4xn62_28f8cwvzf8 - I have some concerns
about phishing (since there's not necessarily any indication about the
source of a given notification), so that may impact our implementation.

void setStatus(imageUrl, optional statusText, optional onClick) - sets the
status bar icon for this worker (possibly limited to one-per-domain?) with
the specified hover text, and a callback which will be invoked if the user
clicks on the icon. Not all platforms have status bars (for example, some
Linux window managers may not), so on those platforms this might not do
anything. User Agents might also just have a single status bar icon for the
browser, which when clicked on displays a window with the status/status text
for all workers (rather than lots of separate icons).

Anyhow, the ideas we have for UI/APIs are still pretty rough - we'll need to
create some mocks and try them out to see what really works.

*- Inter-worker communication*
There isn't currently any way for workers (persistent or otherwise) to talk
to one another without the intervention of a window, even when those workers
exist under the same domain. Additionally, there's no good way for workers
under different domains to talk to one another (a window can use the
cross-domain messaging functionality to talk to other domains, but there's
no analog for this for workers).

This makes it hard for workers cooperatively running under different
subdomains to share resources (authentication info, connections to the
server, aggregated status messages, etc). We already have the idea of
message events having an origin attribute which allows recipient windows to
accept/ignore messages from other domains, but no way for workers to get
ports connecting them to other workers, other than by having them delegated
explicitly by windows. Have there been any past discussions about
inter-worker communication?

Internally we've discussed things like a cross-domain findWorker() API, or
just a cross-domain postMessage() API, both of which would allow specifying
a destination worker by domain + name, but these seem like flawed/cumbersome
solutions.
*
**- Error Handling/Edge cases:*
There are a few places where we need to deal with errors (particularly
network errors):

1) Persistent worker is launched by the user agent at startup, but we can't
load the code (possibly due to a network error). There's no application to
report the error to. In the case of network error, it seems like the user
agent may want to retry (I can imagine that the browser might start up while
the OS is still negotiating for a wireless IP during OS initialization).

2) Worker wants to display a status icon, but the network is down so the
browser can't fetch the URL. One suggestion would be for workers to use data
URIs for their status icons. Failing that, the user agent could display a
generic icon. Similar issues exist for showNotification() as well, if we
allow full HTML in notification popups.

3) Should persistent workers be locked into a single URL forever? Currently
it's an error to try to create a shared worker with a different URL when
there is already a SharedWorker running - this problem is compounded for
persistent workers, because the workers essentially never exit so are stuck
with using the same URL forever. Perhaps it makes sense to make
WorkerGlobalScope.location writeable, to allow workers to control their own
source?

Thanks in advance for your feedback on our approach - it seems like having
persistent workers can enable some really cool application functionality
that you can't really get any other way.

-atw
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.whatwg.org/pipermail/whatwg-whatwg.org/attachments/20090306/ab027aee/attachment.htm>

Received on Friday, 6 March 2009 13:39:33 UTC