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.<br>
<br><span style="font-weight: bold;">- Motivation</span>:<br>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.<br>
<br><span style="font-weight: bold;">- Persistent worker lifetime:<br></span>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.<div>
<br></div><div><span style="font-weight: bold;">- Permissions:</span></div><div>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.</div>
<div><br></div><div>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.</div>
<div><br></div><div>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?<br>
<br><span style="font-weight: bold;">- Changes to worker APIs:<br></span>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.<br>
<br>An application can create a persistent worker via the PersistentWorker() constructor:<br><br> var worker = new PersistentWorker('worker.js', 'core');<br><br>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.<br>
<br>From an entangled Window's standpoint, the persistent workers appear identical to SharedWorkers - they implement the SharedWorker interface and so expose identical APIs.<br><br></div><div><span style="font-weight: bold;">- Worker UI:</span><br>
>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:<div>
<br></div><div>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:</div>
<div><br></div><div>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). </div><div><br></div>
<div>
3) Toast (<a href="http://en.wikipedia.org/wiki/Toast_%28computing%29" target="_blank">http://en.wikipedia.org/wiki/Toast_(computing)</a>) - behavior is similar to the showNotification() API that was previously in HTML5.</div>
<div><div><br></div>
<div>To enable these interactions, we'd add something like the following new APIs to the global scope for persistent workers:<br><div><br></div><div>void open(url, <span style="font-style: italic;">optional </span>target, <span style="font-style: italic;">optional </span>feature, <span style="font-style: italic;">optional </span>replace) - opens a browser window, just like the window.open() API which is available from page context</div>
<br></div><div>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: <a href="http://docs.google.com/Doc?id=dhg4xn62_28f8cwvzf8" target="_blank">http://docs.google.com/Doc?id=dhg4xn62_28f8cwvzf8</a> -
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.<br><br>void setStatus(imageUrl, <span style="font-style: italic;">optional </span>statusText, <span style="font-style: italic;">optional</span> 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). <br>
</div>
<div><br>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.<br><br><b>- Inter-worker communication</b><br>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).<br>
<br>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?<br>
<br>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.<br>
<b><br></b><b>- Error Handling/Edge cases:</b><br>There are a few places where we need to deal with errors (particularly network errors):<br><br>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). <br>
<br>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.<br>
<br>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?<br>
<br></div><div>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.<br><br>-atw<br>
</div><div>
<div>
<br>
</div></div></div></div>