Harden diff-updater against unexpected errors

The diff-updater worker will terminate upon unexpected
error, in order to avoid a stalled updater.
This commit is contained in:
Raymond Hill 2023-10-30 13:47:24 -04:00
parent a45e33cd7a
commit 2344cbdeca
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 29 additions and 11 deletions

View File

@ -1214,6 +1214,13 @@ async function diffUpdater() {
return new Promise(resolve => {
let pendingOps = 0;
const bc = new globalThis.BroadcastChannel('diffUpdater');
const terminate = error => {
worker.terminate();
bc.close();
resolve();
if ( typeof error !== 'string' ) { return; }
ubolog(`Diff updater: terminate because ${error}`);
};
bc.onmessage = ev => {
const data = ev.data;
if ( data.what === 'ready' ) {
@ -1226,6 +1233,10 @@ async function diffUpdater() {
}
return;
}
if ( data.what === 'broken' ) {
terminate(data.error);
return;
}
if ( data.status === 'needtext' ) {
ubolog('Diff updater: need text for', data.name);
assetCacheRead(data.name).then(result => {
@ -1236,7 +1247,7 @@ async function diffUpdater() {
return;
}
if ( data.status === 'updated' ) {
ubolog(`Diff updater: successfully patched ${data.name} using ${data.diffURL}`);
ubolog(`Diff updater: successfully patched ${data.name} using ${data.patchURL} (${data.patchSize})`);
const metadata = extractMetadataFromList(data.text, [
'Last-Modified',
'Expires',
@ -1262,9 +1273,7 @@ async function diffUpdater() {
}
if ( pendingOps !== 0 ) { return; }
ubolog('Diff updater: cycle complete');
worker.terminate();
bc.close();
resolve();
terminate();
};
const worker = new Worker('js/diff-updater.js');
});

View File

@ -173,17 +173,22 @@ async function fetchPatchDetailsFromCDNs(assetDetails) {
if ( Array.isArray(cdnURLs) === false ) { return null; }
if ( cdnURLs.length === 0 ) { return null; }
for ( const cdnURL of suffleArray(cdnURLs) ) {
const diffURL = resolveURL(patchPath, cdnURL);
if ( diffURL === undefined ) { continue; }
const response = await fetch(diffURL).catch(reason => {
const patchURL = resolveURL(patchPath, cdnURL);
if ( patchURL === undefined ) { continue; }
const response = await fetch(patchURL).catch(reason => {
console.error(reason);
});
if ( response === undefined ) { continue; }
if ( response.ok !== true ) { continue; }
const patchText = await response.text();
if ( patchText.length === 0 ) { continue; }
const patchDetails = parsePatch(patchText);
if ( patchDetails === undefined ) { continue; }
return { diffURL, patchDetails };
return {
patchURL,
patchSize: `${(patchText.length / 1000).toFixed(1)} KB`,
patchDetails,
};
}
return null;
}
@ -202,11 +207,12 @@ async function fetchPatchDetails(assetDetails) {
}
async function fetchAndApplyAllPatches(assetDetails) {
const { diffURL, patchDetails } = await fetchPatchDetails(assetDetails);
if ( patchDetails === null ) {
const patchData = await fetchPatchDetails(assetDetails);
if ( patchData === null ) {
assetDetails.error = 'nopatch';
return assetDetails;
}
const { patchDetails } = patchData;
const diffDetails = patchDetails.get(assetDetails.diffName);
if ( diffDetails === undefined ) {
assetDetails.error = 'nodiff';
@ -219,7 +225,8 @@ async function fetchAndApplyAllPatches(assetDetails) {
const outcome = await applyPatchAndValidate(assetDetails, diffDetails);
if ( outcome !== true ) { return assetDetails; }
assetDetails.status = 'updated';
assetDetails.diffURL = diffURL;
assetDetails.patchURL = patchData.patchURL;
assetDetails.patchSize = patchData.patchSize;
return assetDetails;
}
@ -233,6 +240,8 @@ bc.onmessage = ev => {
case 'update':
fetchAndApplyAllPatches(message).then(response => {
bc.postMessage(response);
}).catch(error => {
bc.postMessage({ what: 'broken', error });
});
break;
}