Snappy/AsyncShutdown

From MozillaWiki
Jump to: navigation, search

Our objective

At the moment, Firefox shuts down mostly sequentially. Waiting until an asynchronous task is complete before proceeding with shutdown is complicated and requires spinning the event loop, which is generally Not a Good Idea.

We need to start thinking about a way to shutdown asynchronous services.

Use cases

Asynchronous databases need to be AsyncClosed()

(TBD)

Telemetry data must be saved asynchronously

(TBD)

Telemetry data must be collected after profile-before-change

(TBD)

Downloads API may have a pending "downloads.json" write

Before saving the list of in-progress downloads, the Downloads API waits 1.5 seconds after every change in state of downloads.

Being able to force an asynchronous write of the JSON file in case the browser is closed during the 1.5 seconds window might be useful.

OS.File data must be fully written before we remove the profile

Any call to OS.File.writeAtomic that is placed before the completion of profile-before-change must be completed before we actually remove the profile.

e.g. Bug 911820 for an example of actual dataloss.

Session Restore data must be fully written before we remove the profile

Session Restore collects data during shutdown and must have finished writing that data before we complete profile-before-change.

FHR data must be fully written before we remove the profile

FHR internally maintains a queue of pending database operations. When quit-application is seen, it initiates the shutdown procedure. This effectively schedules a db.close() operation at the end of the queue. During profile-before-change (the last notification before the profile goes away), FHR spins the event loop if the db.close() operation has not yet completed. Telemetry data shows this event loop spinning does not occur often. This is because FHR is typically not actively doing work when shutdown occurs.

The mechanism essentially guarantees a clean shutdown. The queue of database operations consists of complex tasks, which can consist of multiple, chained async function calls. If FHR didn't spin the event loop, it would be up to Storage to wait for all pending statements to complete. The problem here is that Storage isn't aware of the chaining of async events in FHR land. Thus, Storage may pick in inopportune time - say in the middle of a logical transaction - to close the database. This would leave FHR in an inconsistent state.

It is important to note that FHR does not schedule any new I/O during shutdown - it merely completes what was already initiated pre-shutdown.

Work in Progress

AsyncShutdown.jsm

As part of [bug 913899](https://bugzilla.mozilla.org/show_bug.cgi?id=913899), we are introducing an experimental version of AsyncShutdown.jsm, a module designed to make shutdown dependencies more explicit.

AsyncShutdown defines one main primitive, |addBlocker|, which may be used to prevent shutdown from moving past a given stage until some conditions have been satisfied. At the moment, this mechanism is implemented by spinning the event loop intelligently (i.e. only one loop spinning per shutdown phase).

Future developments: Stabilizing, adding support for debugging, adding support for C++ code, applying this to all the JS code on m-c, making public.

Related bugs