libresilient/docs/UPDATING_DURING_DISRUPTION.md

68 wiersze
6.5 KiB
Markdown

# Updating the configuration during disruption
If a website is experiencing an outage, but LibResilient is deployed on it and is working correctly for the visitors whose browsers were able to install and activate it before the disruption started, it is possible to update LibResilient configuration using any alternative transport plugins that were configured originally.
It is not, however, possible to load new plugins that have not been previously loaded based on the previous `config.json`, as this would require a call to `importScripts()` and thus a direct HTTPS request to the original domain.
When loading the configuration file that has been retrieved using alternative transports, LibResilient will reject it if it specifies plugins which have not been loaded previously.
## ServiceWorker API and `importScripts()`
The [Service Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers) allows for updating the service worker script itself and any imported scripts (via [`importScripts()`](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts)) only via a direct HTTPS request to the original domain.
LibResilient expects configuration in a `config.json` file, not in a script, so that it can be retrieved and used without a call to `importScripts()`. This allows updating the configuration (but not code) during disruptions. The `importScripts()` limitation still affects plugin scripts, however: it is not possible to load new plugin scripts while the original website is experiencing disruption or outage.
## LibResilient's Service Worker lifecycle
LibResilient's Service Worker needs the `config.json` configuration script every time it is installed or re-started.
Service Worker installation happens upon loading the website for the first time. Re-start of the Service Worker can happen at any time — it's up to the browser to decide when to stop a Service Worker. This usually happens after all relevant tabs are closed, or some time after the last request even if the tabs are open. A previously installed Service Worker is started whenever there is an event for it to handle; in case of LibResilient that will almost always be a [`fetch` event](https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent).
When a Service Worker is stopped, all context (variables, state, etc) is lost. Only the Service Worker script (in our case, `service-worker.js`) and any scripts imported in it using `importScripts()` remain cached, along with other contents of [the cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache) (and other WebAPIs that are not relevant here).
For LibResilient this means that when an already installed, but stopped, Service Worker gets started again, all plugin initialization needs to happen from scratch. And for that we have to have the `config.json` available.
## Initial loading of the config file
When installing or handling any kind of event, the LibResilient Service Worker script first tries to retrieve the `config.json` file. The first place to look is the cache. If there is a valid `config.json` available there, it is used to configure and initialize the plugins.
If there is no `config.json` available in cache, the only way to get it at this stage (as plugins are not configured yet) is a regular HTTPS `fetch()` request to the original domain. If that works, the retrieved `config.json` is cached for future use (that is, next time when the Service Worker has been stopped and is being started again) and used to configure and initialize the plugins.
If there is no `config.json` available in cache, and the `fetch()` request does not produce a valid `config.json` either, LibResilient falls back to the default config (that is, a pretty trivial set-up using `fetch` and `cache`). At this stage LibResilient Service Worker can start handling requests generated by any open tabs in visitor's browser.
## Updating the config file
After configuring and initializing the plugins, LibResilient checks if the cached `config.json` (if available) is older than 24h, based on the `Date:` header in the response. If it is, it is considered stale, and a new background request for `config.json` is started, this time using the now available already-initialized plugin infrastructure. At this stage, if alternative transport plugins are configured, updated `config.json` can be retrieved even if the original website is experiencing disruptions or downtime.
However, due to the `importScripts()` limitation, if a `config.json` file is retrieved using alternative transport plugins (not via the `fetch` plugin), it is expected *not to* introduce plugins that have not been used before — only to change the configuration of already-loaded plugins. If a plugin that has not been loaded beforehand is present, that `config.json` file is ignored and discarded.
The reasoning behind this is that at this stage we do have a working configuration, as we were able to retrieve `config.json` even though the original website is not available. So it's better to keep using that proven configuration, rather than risk having to call `importScripts()` for a new plugin, which might fail due to original website apparently not being available.
## Pre-loading of plugins in case of disruption
Plugins can be configured in the `config.json` file as `enabled: false`. For example:
```json
{
"plugins": [{
"name": "fetch"
},{
"name": "alt-fetch",
"endpoints": [
"https://example.com/"
]
},{
"name": "redirect",
"enabled": "false"
}],
"loggedComponents": ["service-worker", "fetch", "alt-fetch", "redirect"],
"defaultPluginTimeout": 1000
}
```
This is a pretty simple `config.json` that configures LibResilient to retrieve any website content using regular `fetch()`, but with a fall-back to an `alt-fetch` alternative transport with one endpoint in case the original website is inaccessible.
Note that the `redirect` plugin is configured as disabled. What this means is that its *code* of this plugin will be loaded (using a call to `importScripts()`) into the service worker (as long as the original website is available), but it will not be instantiated nor used for handling any requests.
If the website becomes unavailable for whatever reason, the `alt-fetch` plugin will allow the service worker to pull an updated `config.json` file from and alternative endpoint. That `config.json` file can then activate the (already loaded, but inactive) `redirect` plugin to redirect any and all requests to a completely new domain.