Skip to content

Commit f53ab36

Browse files
committed
chore: prevent spawning concurrent subprocesses
- Update the cache file’s `mtime` before spawning the subprocess. - Add `isChecking` flag to prevent concurrent checks in the same process, including while testing.
1 parent f394814 commit f53ab36

2 files changed

Lines changed: 35 additions & 3 deletions

File tree

src/utils/check-for-updates.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,18 @@ import {VERSION} from '../version.js';
1616
* Notifies the user if an update is available.
1717
* @param message The message to display in the update notification.
1818
*/
19+
let isChecking = false;
20+
21+
/** @internal Reset flag for tests only. */
22+
export function resetUpdateCheckFlagForTesting() {
23+
isChecking = false;
24+
}
25+
1926
export async function checkForUpdates(message: string) {
20-
if (process.env['CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS']) {
27+
if (isChecking || process.env['CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS']) {
2128
return;
2229
}
30+
isChecking = true;
2331

2432
const cachePath = path.join(
2533
os.homedir(),
@@ -49,6 +57,20 @@ export async function checkForUpdates(message: string) {
4957
return;
5058
}
5159

60+
// Update mtime immediately to prevent multiple subprocesses.
61+
try {
62+
const parentDir = path.dirname(cachePath);
63+
await fs.mkdir(parentDir, {recursive: true});
64+
const nowTime = new Date();
65+
if (stats) {
66+
await fs.utimes(cachePath, nowTime, nowTime);
67+
} else {
68+
await fs.writeFile(cachePath, JSON.stringify({version: VERSION}));
69+
}
70+
} catch {
71+
// Ignore errors.
72+
}
73+
5274
// In a separate process, check the latest available version number
5375
// and update the local snapshot accordingly.
5476
const scriptPath = path.join(

tests/check-for-updates.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,26 @@ import child_process from 'node:child_process';
99
import type {Stats} from 'node:fs';
1010
import fs from 'node:fs/promises';
1111
import os from 'node:os';
12-
import {afterEach, describe, it} from 'node:test';
12+
import {afterEach, beforeEach, describe, it} from 'node:test';
1313

1414
import sinon from 'sinon';
1515

16-
import {checkForUpdates} from '../src/utils/check-for-updates.js';
16+
import {
17+
checkForUpdates,
18+
resetUpdateCheckFlagForTesting,
19+
} from '../src/utils/check-for-updates.js';
1720
import {VERSION} from '../src/version.js';
1821

1922
describe('checkForUpdates', () => {
23+
beforeEach(() => {
24+
sinon.stub(fs, 'mkdir').resolves();
25+
sinon.stub(fs, 'utimes').resolves();
26+
sinon.stub(fs, 'writeFile').resolves();
27+
});
28+
2029
afterEach(() => {
2130
sinon.restore();
31+
resetUpdateCheckFlagForTesting();
2232
});
2333

2434
it('does nothing if CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS is set', async () => {

0 commit comments

Comments
 (0)