diff --git a/ee/fleetd-chrome/changes/18775-2-main-threads b/ee/fleetd-chrome/changes/18775-2-main-threads new file mode 100644 index 0000000000..621c94758f --- /dev/null +++ b/ee/fleetd-chrome/changes/18775-2-main-threads @@ -0,0 +1 @@ +Fixed bug where fleetd-chrome sent multiple read requests to Fleet server at the same time. diff --git a/ee/fleetd-chrome/package-lock.json b/ee/fleetd-chrome/package-lock.json index 7d4e507720..1a2b0ffc91 100644 --- a/ee/fleetd-chrome/package-lock.json +++ b/ee/fleetd-chrome/package-lock.json @@ -8,6 +8,7 @@ "name": "fleetd-for-chrome", "version": "1.3.0", "dependencies": { + "async-mutex": "^0.5.0", "dotenv": "^16.0.3", "wa-sqlite": "github:rhashimoto/wa-sqlite#v0.9.11" }, @@ -2066,6 +2067,14 @@ "node": "*" } }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -8137,8 +8146,7 @@ "node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "dev": true + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" }, "node_modules/type-detect": { "version": "4.0.8", diff --git a/ee/fleetd-chrome/package.json b/ee/fleetd-chrome/package.json index 18e6dfe634..ea7bbf7336 100644 --- a/ee/fleetd-chrome/package.json +++ b/ee/fleetd-chrome/package.json @@ -3,6 +3,7 @@ "description": "Extension for Fleetd on ChromeOS", "version": "1.3.0", "dependencies": { + "async-mutex": "^0.5.0", "dotenv": "^16.0.3", "wa-sqlite": "github:rhashimoto/wa-sqlite#v0.9.11" }, diff --git a/ee/fleetd-chrome/src/background.ts b/ee/fleetd-chrome/src/background.ts index 977c052728..d946d73474 100644 --- a/ee/fleetd-chrome/src/background.ts +++ b/ee/fleetd-chrome/src/background.ts @@ -1,4 +1,5 @@ import VirtualDatabase from "./db"; +import {Mutex, withTimeout, tryAcquire, E_ALREADY_LOCKED} from 'async-mutex'; // ENV Vars declare var FLEET_URL: string; @@ -236,6 +237,12 @@ class NodeInvalidError extends Error { } } +// We use a mutex to ensure that only one instance of main is running at a time. +const mutexWithTimeout = withTimeout(new Mutex(), 60 * 1000) // 60 second timeout +async function runExclusive(callback: () => Promise) { + await tryAcquire(mutexWithTimeout).runExclusive(callback) +} + // QUESTION maybe we should use one of the persistence mechanisms described in // https://stackoverflow.com/a/66618269/491710? The "offscreen API" mechanism might be useful. On // the other hand, this seems to work decently well and adding the complexity might not be worth it. @@ -247,16 +254,20 @@ class NodeInvalidError extends Error { let mainTimeout: ReturnType; const mainLoop = async () => { try { - await main(); - clearTimeout(mainTimeout); - mainTimeout = setTimeout(mainLoop, 10 * 1000); + await runExclusive(main); } catch (err) { + if (err === E_ALREADY_LOCKED) { + console.info("'main' mutex already locked, skipping run") + return + } console.error(err); if (err.message === MEMORY_RUNTIME_ERROR_MESSAGE) { console.info("Restarting DB after wa-sqlite RuntimeError") await initDB(); } } + clearTimeout(mainTimeout); + mainTimeout = setTimeout(mainLoop, 10 * 1000); }; mainLoop();