Skip to content

Commit

Permalink
Workaround ServiceWorker hanging after a while by keeping it alive pe…
Browse files Browse the repository at this point in the history
…riodically.

The MessageChannel is re-created each time.
It prevents the ServiceWorker from being restarted and losing its variables
See #145
  • Loading branch information
mossroy committed Apr 9, 2017
1 parent bbe7610 commit 8efc6a6
Showing 1 changed file with 33 additions and 10 deletions.
43 changes: 33 additions & 10 deletions www/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ define(['jquery', 'abstractBackend', 'util', 'uiUtil', 'cookies','geometry','osa
* @type Float
*/
var DEFAULT_MAX_DISTANCE_ARTICLES_NEARBY = 0.01;

/**
* The delay (in milliseconds) between two "keepalive" messages
* sent to the ServiceWorker (so that it is not stopped by
* the browser, and keeps the MessageChannel to communicate
* with the application)
* @type Integer
*/
var DELAY_BETWEEN_KEEPALIVE_SERVICEWORKER = 30000;

/**
* @type LocalArchive|ZIMArchive
Expand Down Expand Up @@ -302,6 +311,27 @@ define(['jquery', 'abstractBackend', 'util', 'uiUtil', 'cookies','geometry','osa

var contentInjectionMode;

/**
* Send an 'init' message to the ServiceWorker with a new MessageChannel
* to initialize it, or to keep it alive.
* This MessageChannel allows a 2-way communication between the ServiceWorker
* and the application
*/
function initOrKeepAliveServiceWorker() {
if (contentInjectionMode === 'serviceworker') {
// Create a new messageChannel
var tmpMessageChannel = new MessageChannel();
tmpMessageChannel.port1.onmessage = handleMessageChannelMessage;
// Send the init message to the ServiceWorker, with this MessageChannel as a parameter
navigator.serviceWorker.controller.postMessage({'action': 'init'}, [tmpMessageChannel.port2]);
messageChannel = tmpMessageChannel;
console.log("init message sent to ServiceWorker");
// Schedule to do it again regularly to keep the 2-way communication alive.
// See https://github.com/kiwix/kiwix-html5/issues/145 to understand why
setTimeout(initOrKeepAliveServiceWorker, DELAY_BETWEEN_KEEPALIVE_SERVICEWORKER);
}
}

/**
* Sets the given injection mode.
* This involves registering (or re-enabling) the Service Worker if necessary
Expand Down Expand Up @@ -332,13 +362,6 @@ define(['jquery', 'abstractBackend', 'util', 'uiUtil', 'cookies','geometry','osa
return;
}

if (!messageChannel) {
// Let's create the messageChannel for the 2-way communication
// with the Service Worker
messageChannel = new MessageChannel();
messageChannel.port1.onmessage = handleMessageChannelMessage;
}

if (!isServiceWorkerReady()) {
$('#serviceWorkerStatus').html("ServiceWorker API available : trying to register it...");
navigator.serviceWorker.register('../service-worker.js').then(function (reg) {
Expand All @@ -351,9 +374,9 @@ define(['jquery', 'abstractBackend', 'util', 'uiUtil', 'cookies','geometry','osa
var serviceWorker = reg.installing || reg.waiting || reg.active;
serviceWorker.addEventListener('statechange', function(statechangeevent) {
if (statechangeevent.target.state === 'activated') {
console.log("try to post an init message to ServiceWorker");
navigator.serviceWorker.controller.postMessage({'action': 'init'}, [messageChannel.port2]);
console.log("init message sent to ServiceWorker");
// Create the MessageChannel
// and send the 'init' message to the ServiceWorker
initOrKeepAliveServiceWorker();
}
});
}, function (err) {
Expand Down

0 comments on commit 8efc6a6

Please sign in to comment.