Skip to content

Commit 20e4664

Browse files
committed
chore(mongodb-downloader): use a lockfile to prevent redundant parallel downloads
1 parent 71e0a4d commit 20e4664

File tree

5 files changed

+780
-121
lines changed

5 files changed

+780
-121
lines changed

package-lock.json

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

packages/mongodb-downloader/package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@
5353
},
5454
"dependencies": {
5555
"debug": "^4.4.0",
56-
"tar": "^6.1.15",
5756
"decompress": "^4.2.1",
58-
"mongodb-download-url": "^1.6.3",
59-
"node-fetch": "^2.7.0"
57+
"node-fetch": "^2.7.0",
58+
"promise-retry": "^2.0.1",
59+
"signal-exit": "^4.1.0",
60+
"tar": "^6.1.15",
61+
"mongodb-download-url": "^1.6.3"
6062
},
6163
"devDependencies": {
6264
"@mongodb-js/eslint-config-devtools": "0.9.12",
@@ -67,6 +69,8 @@
6769
"@types/decompress": "^4.2.4",
6870
"@types/mocha": "^9.1.1",
6971
"@types/node": "^22.15.30",
72+
"@types/promise-retry": "^1.1.6",
73+
"@types/signal-exit": "^3.0.4",
7074
"@types/tar": "^6.1.5",
7175
"depcheck": "^1.4.7",
7276
"eslint": "^7.25.0",
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { expect } from 'chai';
2+
import { promises as fs } from 'fs';
3+
import path from 'path';
4+
import os from 'os';
5+
import { MongoDbDownloader } from './index';
6+
7+
describe('downloader with Locking', function () {
8+
this.timeout(60000);
9+
10+
let tmpDir: string;
11+
12+
beforeEach(async function () {
13+
tmpDir = path.join(os.tmpdir(), `download-integration-tests-${Date.now()}`);
14+
await fs.mkdir(tmpDir, { recursive: true });
15+
});
16+
const version = '8.2.0';
17+
18+
afterEach(async function () {
19+
try {
20+
await fs.rm(tmpDir, { recursive: true });
21+
} catch {
22+
// Ignore cleanup errors
23+
}
24+
});
25+
26+
it('should prevent concurrent downloads of the same version', async function () {
27+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
28+
29+
const results = await Promise.all([
30+
downloader.downloadMongoDbWithVersionInfo(version),
31+
downloader.downloadMongoDbWithVersionInfo(version),
32+
downloader.downloadMongoDbWithVersionInfo(version),
33+
]);
34+
35+
// All results should be identical
36+
expect(results[0].version).to.equal(version);
37+
expect(results[1].version).to.equal(version);
38+
expect(results[2].version).to.equal(version);
39+
40+
expect(results[0].downloadedBinDir).to.equal(results[1].downloadedBinDir);
41+
expect(results[1].downloadedBinDir).to.equal(results[2].downloadedBinDir);
42+
43+
// Verify the downloaded directory exists and contains mongod
44+
expect(await fs.stat(results[0].downloadedBinDir)).to.be.ok;
45+
expect(await fs.stat(path.join(results[0].downloadedBinDir, 'mongod'))).to
46+
.be.ok;
47+
});
48+
49+
it('should wait for existing download to complete', async function () {
50+
// First, download MongoDB normally
51+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
52+
const result = await downloader.downloadMongoDbWithVersionInfo(version);
53+
54+
expect(result.version).to.equal(version);
55+
expect(result.downloadedBinDir).to.be.a('string');
56+
57+
// Verify the downloaded directory exists and contains mongod
58+
expect(await fs.stat(result.downloadedBinDir)).to.be.ok;
59+
expect(await fs.stat(path.join(result.downloadedBinDir, 'mongod'))).to.be
60+
.ok;
61+
});
62+
63+
it('should skip download if already completed', async function () {
64+
// First download
65+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
66+
const result1 = await downloader.downloadMongoDbWithVersionInfo(version);
67+
68+
// Second download should use cached result
69+
const result2 = await downloader.downloadMongoDbWithVersionInfo(version);
70+
71+
expect(result1.version).to.equal(version);
72+
expect(result2.version).to.equal(version);
73+
expect(result1.downloadedBinDir).to.equal(result2.downloadedBinDir);
74+
75+
// Verify the downloaded directory exists and contains mongod
76+
expect(await fs.stat(result1.downloadedBinDir)).to.be.ok;
77+
expect(await fs.stat(path.join(result1.downloadedBinDir, 'mongod'))).to.be
78+
.ok;
79+
});
80+
81+
it('should handle different versions independently', async function () {
82+
const version2 = '8.1.0';
83+
84+
// Download different versions
85+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
86+
const [result1, result2] = await Promise.all([
87+
downloader.downloadMongoDbWithVersionInfo(version),
88+
downloader.downloadMongoDbWithVersionInfo(version2),
89+
]);
90+
91+
expect(result1.version).to.equal(version);
92+
expect(result2.version).to.equal(version2);
93+
expect(result1.downloadedBinDir).to.not.equal(result2.downloadedBinDir);
94+
95+
// Verify both downloaded directories exist and contain mongod
96+
expect(await fs.stat(result1.downloadedBinDir)).to.be.ok;
97+
expect(await fs.stat(path.join(result1.downloadedBinDir, 'mongod'))).to.be
98+
.ok;
99+
expect(await fs.stat(result2.downloadedBinDir)).to.be.ok;
100+
expect(await fs.stat(path.join(result2.downloadedBinDir, 'mongod'))).to.be
101+
.ok;
102+
});
103+
104+
it('should handle promise caching correctly', async function () {
105+
const version = '8.2.0';
106+
107+
// Start multiple downloads in sequence (not parallel)
108+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
109+
const result1 = await downloader.downloadMongoDbWithVersionInfo(version);
110+
const result2 = await downloader.downloadMongoDbWithVersionInfo(version);
111+
const result3 = await downloader.downloadMongoDbWithVersionInfo(version);
112+
113+
// All should return the same result
114+
expect(result1.version).to.equal(version);
115+
expect(result2.version).to.equal(version);
116+
expect(result3.version).to.equal(version);
117+
118+
expect(result1.downloadedBinDir).to.equal(result2.downloadedBinDir);
119+
expect(result2.downloadedBinDir).to.equal(result3.downloadedBinDir);
120+
121+
// Verify the downloaded directory exists and contains mongod
122+
expect(await fs.stat(result1.downloadedBinDir)).to.be.ok;
123+
expect(await fs.stat(path.join(result1.downloadedBinDir, 'mongod'))).to.be
124+
.ok;
125+
});
126+
});

0 commit comments

Comments
 (0)