From 8ade1b69228eab65aba7b21f552b7883b6b8a73f Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 12 Jan 2023 17:31:13 -0800 Subject: [PATCH] Only retry for the specific thing raising EBUSY Fix: https://github.com/isaacs/rimraf/issues/187 --- src/fs.ts | 5 ++++- src/retry-busy.ts | 9 +++++++-- test/retry-busy.js | 8 ++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/fs.ts b/src/fs.ts index fb5c450e..4ee7128b 100644 --- a/src/fs.ts +++ b/src/fs.ts @@ -2,7 +2,10 @@ import fs from 'fs' -export type FsError = Error & { code?: string } +export type FsError = Error & { + code?: string + path?: string +} // sync ones just take the sync version from node export { diff --git a/src/retry-busy.ts b/src/retry-busy.ts index 117f6f9b..78f27c65 100644 --- a/src/retry-busy.ts +++ b/src/retry-busy.ts @@ -24,7 +24,7 @@ export const retryBusy = (fn: (path: string) => Promise) => { return await fn(path) } catch (er) { const fer = er as FsError - if (fer?.code && codes.has(fer.code)) { + if (fer?.path === path && fer?.code && codes.has(fer.code)) { backoff = Math.ceil(backoff * rate) total = backoff + total if (total < mbo) { @@ -57,7 +57,12 @@ export const retryBusySync = (fn: (path: string) => any) => { return fn(path) } catch (er) { const fer = er as FsError - if (fer?.code && codes.has(fer.code) && retries < max) { + if ( + fer?.path === path && + fer?.code && + codes.has(fer.code) && + retries < max + ) { retries++ continue } diff --git a/test/retry-busy.js b/test/retry-busy.js index 3a969e80..85389b38 100644 --- a/test/retry-busy.js +++ b/test/retry-busy.js @@ -51,7 +51,7 @@ t.test('retry when known error code thrown', t => { thrown = true t.equal(calls, 0, 'first call') calls++ - throw Object.assign(new Error(code), { code }) + throw Object.assign(new Error(code), { path: a, code }) } else { t.equal(calls, 1, 'second call') calls++ @@ -83,10 +83,10 @@ t.test('retry and eventually give up', t => { t.equal(a, arg, 'got first argument') t.equal(b, undefined, 'did not get another argument') calls++ - throw Object.assign(new Error(code), { code }) + throw Object.assign(new Error(code), { path: a, code }) } const rBS = retryBusySync(method) - t.throws(() => rBS(arg, opt), { code }) + t.throws(() => rBS(arg, opt), { path: arg, code }) t.equal(calls, 3) calls = 0 const rB = retryBusy(method) @@ -101,7 +101,7 @@ t.test('throw unknown error gives up right away', async t => { const method = (a, b) => { t.equal(a, arg, 'got first argument') t.equal(b, undefined, 'did not get another argument') - throw Object.assign(new Error('nope'), { code: 'nope' }) + throw Object.assign(new Error('nope'), { path: a, code: 'nope' }) } const rBS = retryBusySync(method) t.throws(() => rBS(arg, opt), { code: 'nope' })