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 => { return new Promise(resolve => {
let pendingOps = 0; let pendingOps = 0;
const bc = new globalThis.BroadcastChannel('diffUpdater'); 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 => { bc.onmessage = ev => {
const data = ev.data; const data = ev.data;
if ( data.what === 'ready' ) { if ( data.what === 'ready' ) {
@ -1226,6 +1233,10 @@ async function diffUpdater() {
} }
return; return;
} }
if ( data.what === 'broken' ) {
terminate(data.error);
return;
}
if ( data.status === 'needtext' ) { if ( data.status === 'needtext' ) {
ubolog('Diff updater: need text for', data.name); ubolog('Diff updater: need text for', data.name);
assetCacheRead(data.name).then(result => { assetCacheRead(data.name).then(result => {
@ -1236,7 +1247,7 @@ async function diffUpdater() {
return; return;
} }
if ( data.status === 'updated' ) { 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, [ const metadata = extractMetadataFromList(data.text, [
'Last-Modified', 'Last-Modified',
'Expires', 'Expires',
@ -1262,9 +1273,7 @@ async function diffUpdater() {
} }
if ( pendingOps !== 0 ) { return; } if ( pendingOps !== 0 ) { return; }
ubolog('Diff updater: cycle complete'); ubolog('Diff updater: cycle complete');
worker.terminate(); terminate();
bc.close();
resolve();
}; };
const worker = new Worker('js/diff-updater.js'); 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 ( Array.isArray(cdnURLs) === false ) { return null; }
if ( cdnURLs.length === 0 ) { return null; } if ( cdnURLs.length === 0 ) { return null; }
for ( const cdnURL of suffleArray(cdnURLs) ) { for ( const cdnURL of suffleArray(cdnURLs) ) {
const diffURL = resolveURL(patchPath, cdnURL); const patchURL = resolveURL(patchPath, cdnURL);
if ( diffURL === undefined ) { continue; } if ( patchURL === undefined ) { continue; }
const response = await fetch(diffURL).catch(reason => { const response = await fetch(patchURL).catch(reason => {
console.error(reason); console.error(reason);
}); });
if ( response === undefined ) { continue; } if ( response === undefined ) { continue; }
if ( response.ok !== true ) { continue; } if ( response.ok !== true ) { continue; }
const patchText = await response.text(); const patchText = await response.text();
if ( patchText.length === 0 ) { continue; }
const patchDetails = parsePatch(patchText); const patchDetails = parsePatch(patchText);
if ( patchDetails === undefined ) { continue; } if ( patchDetails === undefined ) { continue; }
return { diffURL, patchDetails }; return {
patchURL,
patchSize: `${(patchText.length / 1000).toFixed(1)} KB`,
patchDetails,
};
} }
return null; return null;
} }
@ -202,11 +207,12 @@ async function fetchPatchDetails(assetDetails) {
} }
async function fetchAndApplyAllPatches(assetDetails) { async function fetchAndApplyAllPatches(assetDetails) {
const { diffURL, patchDetails } = await fetchPatchDetails(assetDetails); const patchData = await fetchPatchDetails(assetDetails);
if ( patchDetails === null ) { if ( patchData === null ) {
assetDetails.error = 'nopatch'; assetDetails.error = 'nopatch';
return assetDetails; return assetDetails;
} }
const { patchDetails } = patchData;
const diffDetails = patchDetails.get(assetDetails.diffName); const diffDetails = patchDetails.get(assetDetails.diffName);
if ( diffDetails === undefined ) { if ( diffDetails === undefined ) {
assetDetails.error = 'nodiff'; assetDetails.error = 'nodiff';
@ -219,7 +225,8 @@ async function fetchAndApplyAllPatches(assetDetails) {
const outcome = await applyPatchAndValidate(assetDetails, diffDetails); const outcome = await applyPatchAndValidate(assetDetails, diffDetails);
if ( outcome !== true ) { return assetDetails; } if ( outcome !== true ) { return assetDetails; }
assetDetails.status = 'updated'; assetDetails.status = 'updated';
assetDetails.diffURL = diffURL; assetDetails.patchURL = patchData.patchURL;
assetDetails.patchSize = patchData.patchSize;
return assetDetails; return assetDetails;
} }
@ -233,6 +240,8 @@ bc.onmessage = ev => {
case 'update': case 'update':
fetchAndApplyAllPatches(message).then(response => { fetchAndApplyAllPatches(message).then(response => {
bc.postMessage(response); bc.postMessage(response);
}).catch(error => {
bc.postMessage({ what: 'broken', error });
}); });
break; break;
} }