Skip to content

Commit 8a27b45

Browse files
committed
Use lockfile when downloading CodeQL distribution
1 parent 7e4180b commit 8a27b45

File tree

4 files changed

+96
-4
lines changed

4 files changed

+96
-4
lines changed

extensions/ql-vscode/package-lock.json

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/ql-vscode/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,7 @@
19861986
"msw": "^2.2.13",
19871987
"nanoid": "^5.0.7",
19881988
"p-queue": "^8.0.1",
1989+
"proper-lockfile": "^4.1.2",
19891990
"react": "^18.3.1",
19901991
"react-dom": "^18.3.1",
19911992
"semver": "^7.6.2",
@@ -2040,6 +2041,7 @@
20402041
"@types/js-yaml": "^4.0.6",
20412042
"@types/nanoid": "^3.0.0",
20422043
"@types/node": "20.16.*",
2044+
"@types/proper-lockfile": "^4.1.4",
20432045
"@types/react": "^18.3.1",
20442046
"@types/react-dom": "^18.3.0",
20452047
"@types/sarif": "^2.1.2",

extensions/ql-vscode/src/codeql-cli/distribution.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import type { WriteStream } from "fs";
2-
import { createWriteStream, mkdtemp, pathExists, remove } from "fs-extra";
2+
import {
3+
createWriteStream,
4+
mkdtemp,
5+
pathExists,
6+
remove,
7+
writeJson,
8+
} from "fs-extra";
39
import { tmpdir } from "os";
410
import { delimiter, dirname, join } from "path";
511
import { Range, satisfies } from "semver";
@@ -28,6 +34,7 @@ import { reportUnzipProgress } from "../common/vscode/unzip-progress";
2834
import type { Release } from "./distribution/release";
2935
import { ReleasesApiConsumer } from "./distribution/releases-api-consumer";
3036
import { createTimeoutSignal } from "../common/fetch-stream";
37+
import { withDistributionUpdateLock } from "./lock";
3138

3239
/**
3340
* distribution.ts
@@ -350,9 +357,24 @@ class ExtensionSpecificDistributionManager {
350357
release: Release,
351358
progressCallback?: ProgressCallback,
352359
): Promise<void> {
353-
await this.downloadDistribution(release, progressCallback);
354-
// Store the installed release within the global extension state.
355-
await this.storeInstalledRelease(release);
360+
const distributionStatePath = join(
361+
this.extensionContext.globalStorageUri.fsPath,
362+
ExtensionSpecificDistributionManager._distributionStateFilename,
363+
);
364+
if (!(await pathExists(distributionStatePath))) {
365+
// This may result in a race condition, but when this happens both processes should write the same file.
366+
await writeJson(distributionStatePath, {});
367+
}
368+
369+
await withDistributionUpdateLock(
370+
// .lock will be appended to this filename
371+
distributionStatePath,
372+
async () => {
373+
await this.downloadDistribution(release, progressCallback);
374+
// Store the installed release within the global extension state.
375+
await this.storeInstalledRelease(release);
376+
},
377+
);
356378
}
357379

358380
private async downloadDistribution(
@@ -615,6 +637,7 @@ class ExtensionSpecificDistributionManager {
615637
"distributionFolderIndex";
616638
private static readonly _installedReleaseStateKey = "distributionRelease";
617639
private static readonly _codeQlExtractedFolderName = "codeql";
640+
private static readonly _distributionStateFilename = "distribution.json";
618641
}
619642

620643
/*
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { lock } from "proper-lockfile";
2+
3+
export async function withDistributionUpdateLock(
4+
lockFile: string,
5+
f: () => Promise<void>,
6+
) {
7+
const release = await lock(lockFile, {
8+
stale: 60_000, // 1 minute. We can take the lock longer than this because that's based on the update interval.
9+
update: 10_000, // 10 seconds
10+
retries: {
11+
minTimeout: 10_000,
12+
maxTimeout: 60_000,
13+
retries: 100,
14+
},
15+
});
16+
17+
try {
18+
await f();
19+
} finally {
20+
await release();
21+
}
22+
}

0 commit comments

Comments
 (0)