diff --git a/packages/mongodb-log-writer/src/mongo-log-manager.spec.ts b/packages/mongodb-log-writer/src/mongo-log-manager.spec.ts index 81e22741..39eea94a 100644 --- a/packages/mongodb-log-writer/src/mongo-log-manager.spec.ts +++ b/packages/mongodb-log-writer/src/mongo-log-manager.spec.ts @@ -316,6 +316,32 @@ describe('MongoLogManager', function () { expect(await getFilesState(paths)).to.equal('0000111111'); }); + it('skips checking file storage if retentionGB is set to Infinity', async function () { + const statStub = sinon.stub(fs, 'stat'); + + const manager = new MongoLogManager({ + directory, + retentionDays, + maxLogFileCount: 1000, + retentionGB: Infinity, + onwarn, + onerror, + }); + + const offset = Math.floor(Date.now() / 1000); + for (let i = 0; i < 10; i++) { + const filename = path.join( + directory, + ObjectId.createFromTime(offset - i).toHexString() + '_log' + ); + await fs.writeFile(filename, ''); + } + + await manager.cleanupOldLogFiles(); + + expect(statStub).not.called; + }); + describe('with a random file order', function () { let paths: string[] = []; const times = [92, 90, 1, 2, 3, 91]; diff --git a/packages/mongodb-log-writer/src/mongo-log-manager.ts b/packages/mongodb-log-writer/src/mongo-log-manager.ts index 942a7521..41b4d374 100644 --- a/packages/mongodb-log-writer/src/mongo-log-manager.ts +++ b/packages/mongodb-log-writer/src/mongo-log-manager.ts @@ -62,7 +62,10 @@ export class MongoLogManager { } /** Clean up log files older than `retentionDays`. */ - async cleanupOldLogFiles(maxDurationMs = 5_000, remainingRetries = 1): Promise { + async cleanupOldLogFiles( + maxDurationMs = 5_000, + remainingRetries = 1 + ): Promise { const deletionStartTimestamp = Date.now(); // Delete files older than N days const deletionCutoffTimestamp = @@ -84,7 +87,13 @@ export class MongoLogManager { fileSize: number | undefined; }>((a, b) => a.fileTimestamp - b.fileTimestamp); - let usedStorageSize = this._options.retentionGB ? 0 : -Infinity; + const hasRetentionGB = + !!this._options.retentionGB && isFinite(this._options.retentionGB); + const hasMaxLogFileCount = + !!this._options.maxLogFileCount && + isFinite(this._options.maxLogFileCount); + + let usedStorageSize = hasRetentionGB ? 0 : -Infinity; try { for await (const dirent of dirHandle) { @@ -93,7 +102,7 @@ export class MongoLogManager { // where lots and lots of log files end up and filesystem operations happen // with network latency. if (Date.now() - deletionStartTimestamp > maxDurationMs) break; - + if (!dirent.isFile()) continue; const logRegExp = new RegExp( `^${this.prefix}(?[a-f0-9]{24})_log(\\.gz)?$`, @@ -101,10 +110,10 @@ export class MongoLogManager { ); const { id } = logRegExp.exec(dirent.name)?.groups ?? {}; if (!id) continue; - + const fileTimestamp = +new ObjectId(id).getTimestamp(); const fullPath = path.join(dir, dirent.name); - + // If the file is older than expected, delete it. If the file is recent, // add it to the list of seen files, and if that list is too large, remove // the least recent file we've seen so far. @@ -112,9 +121,9 @@ export class MongoLogManager { await this.deleteFile(fullPath); continue; } - + let fileSize: number | undefined; - if (this._options.retentionGB) { + if (hasRetentionGB) { try { fileSize = (await fs.stat(fullPath)).size; usedStorageSize += fileSize; @@ -123,12 +132,13 @@ export class MongoLogManager { continue; } } - - if (this._options.maxLogFileCount || this._options.retentionGB) { + + if (hasMaxLogFileCount || hasRetentionGB) { leastRecentFileHeap.push({ fullPath, fileTimestamp, fileSize }); } - + if ( + hasMaxLogFileCount && this._options.maxLogFileCount && leastRecentFileHeap.size() > this._options.maxLogFileCount ) { @@ -145,11 +155,14 @@ export class MongoLogManager { // To handle such scenarios, we will catch lstat errors and retry cleaning up // to let different processes reach out to different log files. if (statErr.code === 'ENOENT' && remainingRetries > 0) { - await this.cleanupOldLogFiles(maxDurationMs - (Date.now() - deletionStartTimestamp), remainingRetries - 1); + await this.cleanupOldLogFiles( + maxDurationMs - (Date.now() - deletionStartTimestamp), + remainingRetries - 1 + ); } } - if (this._options.retentionGB) { + if (hasRetentionGB && this._options.retentionGB) { const storageSizeLimit = this._options.retentionGB * 1024 * 1024 * 1024; for (const file of leastRecentFileHeap) {