Skip to content

Commit fa16082

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

File tree

5 files changed

+782
-121
lines changed

5 files changed

+782
-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: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
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+
// No mocking - let tests download real MongoDB binaries
17+
});
18+
const version = '8.2.0';
19+
20+
afterEach(async function () {
21+
try {
22+
await fs.rm(tmpDir, { recursive: true });
23+
} catch {
24+
// Ignore cleanup errors
25+
}
26+
});
27+
28+
it('should prevent concurrent downloads of the same version', async function () {
29+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
30+
31+
const results = await Promise.all([
32+
downloader.downloadMongoDbWithVersionInfo(version),
33+
downloader.downloadMongoDbWithVersionInfo(version),
34+
downloader.downloadMongoDbWithVersionInfo(version),
35+
]);
36+
37+
// All results should be identical
38+
expect(results[0].version).to.equal(version);
39+
expect(results[1].version).to.equal(version);
40+
expect(results[2].version).to.equal(version);
41+
42+
expect(results[0].downloadedBinDir).to.equal(results[1].downloadedBinDir);
43+
expect(results[1].downloadedBinDir).to.equal(results[2].downloadedBinDir);
44+
45+
// Verify the downloaded directory exists and contains mongod
46+
expect(await fs.stat(results[0].downloadedBinDir)).to.be.ok;
47+
expect(await fs.stat(path.join(results[0].downloadedBinDir, 'mongod'))).to
48+
.be.ok;
49+
});
50+
51+
it('should wait for existing download to complete', async function () {
52+
// First, download MongoDB normally
53+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
54+
const result = await downloader.downloadMongoDbWithVersionInfo(version);
55+
56+
expect(result.version).to.equal(version);
57+
expect(result.downloadedBinDir).to.be.a('string');
58+
59+
// Verify the downloaded directory exists and contains mongod
60+
expect(await fs.stat(result.downloadedBinDir)).to.be.ok;
61+
expect(await fs.stat(path.join(result.downloadedBinDir, 'mongod'))).to.be
62+
.ok;
63+
});
64+
65+
it('should skip download if already completed', async function () {
66+
// First download
67+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
68+
const result1 = await downloader.downloadMongoDbWithVersionInfo(version);
69+
70+
// Second download should use cached result
71+
const result2 = await downloader.downloadMongoDbWithVersionInfo(version);
72+
73+
expect(result1.version).to.equal(version);
74+
expect(result2.version).to.equal(version);
75+
expect(result1.downloadedBinDir).to.equal(result2.downloadedBinDir);
76+
77+
// Verify the downloaded directory exists and contains mongod
78+
expect(await fs.stat(result1.downloadedBinDir)).to.be.ok;
79+
expect(await fs.stat(path.join(result1.downloadedBinDir, 'mongod'))).to.be
80+
.ok;
81+
});
82+
83+
it('should handle different versions independently', async function () {
84+
const version2 = '8.1.0';
85+
86+
// Download different versions
87+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
88+
const [result1, result2] = await Promise.all([
89+
downloader.downloadMongoDbWithVersionInfo(version),
90+
downloader.downloadMongoDbWithVersionInfo(version2),
91+
]);
92+
93+
expect(result1.version).to.equal(version);
94+
expect(result2.version).to.equal(version2);
95+
expect(result1.downloadedBinDir).to.not.equal(result2.downloadedBinDir);
96+
97+
// Verify both downloaded directories exist and contain mongod
98+
expect(await fs.stat(result1.downloadedBinDir)).to.be.ok;
99+
expect(await fs.stat(path.join(result1.downloadedBinDir, 'mongod'))).to.be
100+
.ok;
101+
expect(await fs.stat(result2.downloadedBinDir)).to.be.ok;
102+
expect(await fs.stat(path.join(result2.downloadedBinDir, 'mongod'))).to.be
103+
.ok;
104+
});
105+
106+
it('should handle promise caching correctly', async function () {
107+
const version = '8.2.0';
108+
109+
// Start multiple downloads in sequence (not parallel)
110+
const downloader = new MongoDbDownloader({ tmpdir: tmpDir });
111+
const result1 = await downloader.downloadMongoDbWithVersionInfo(version);
112+
const result2 = await downloader.downloadMongoDbWithVersionInfo(version);
113+
const result3 = await downloader.downloadMongoDbWithVersionInfo(version);
114+
115+
// All should return the same result
116+
expect(result1.version).to.equal(version);
117+
expect(result2.version).to.equal(version);
118+
expect(result3.version).to.equal(version);
119+
120+
expect(result1.downloadedBinDir).to.equal(result2.downloadedBinDir);
121+
expect(result2.downloadedBinDir).to.equal(result3.downloadedBinDir);
122+
123+
// Verify the downloaded directory exists and contains mongod
124+
expect(await fs.stat(result1.downloadedBinDir)).to.be.ok;
125+
expect(await fs.stat(path.join(result1.downloadedBinDir, 'mongod'))).to.be
126+
.ok;
127+
});
128+
});

0 commit comments

Comments
 (0)