From 6a245f943eb1a5d18cd624e127fb4924b5d1662e Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Tue, 6 Sep 2022 13:14:49 +0200 Subject: [PATCH] fix: consider locks acquired in the future to be stale --- lib/lockfile.js | 4 +++- test/lock.test.js | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/lockfile.js b/lib/lockfile.js index 97b6637..8e67f34 100644 --- a/lib/lockfile.js +++ b/lib/lockfile.js @@ -82,7 +82,9 @@ function acquireLock(file, options, callback) { } function isLockStale(stat, options) { - return stat.mtime.getTime() < Date.now() - options.stale; + // On some systems it can happen that the time is rewinded after a hard reboot + // This would leave us with a lock that seems to be held at a future time. + return Math.abs(Date.now() - stat.mtime.getTime()) > options.stale; } function removeLock(file, options, callback) { diff --git a/test/lock.test.js b/test/lock.test.js index ec4accb..fc22336 100644 --- a/test/lock.test.js +++ b/test/lock.test.js @@ -183,6 +183,19 @@ it('should remove and acquire over stale locks', async () => { expect(fs.statSync(`${tmpDir}/foo.lock`).mtime.getTime()).toBeGreaterThan(Date.now() - 3000); }); +it('should remove and acquire locks from the future', async () => { + const mtime = new Date(Date.now() + 60000); + + fs.writeFileSync(`${tmpDir}/foo`, ''); + fs.mkdirSync(`${tmpDir}/foo.lock`); + fs.utimesSync(`${tmpDir}/foo.lock`, mtime, mtime); + + await lockfile.lock(`${tmpDir}/foo`); + + expect(fs.statSync(`${tmpDir}/foo.lock`).mtime.getTime()).toBeGreaterThan(Date.now() - 3000); + expect(fs.statSync(`${tmpDir}/foo.lock`).mtime.getTime()).toBeLessThan(Date.now() + 3000); +}); + it('should retry if the lockfile was removed when verifying staleness', async () => { const mtime = new Date(Date.now() - 60000); let count = 0;