Skip to content

Commit

Permalink
fix: start retrying immediately, stop after 10 attempts
Browse files Browse the repository at this point in the history
PR-URL: #217
Credit: @nlf
Close: #217
Reviewed-by: @isaacs, @wraithgar
  • Loading branch information
nlf authored and isaacs committed Aug 5, 2021
1 parent e9a394b commit e4ee5d6
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
45 changes: 26 additions & 19 deletions graceful-fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,13 @@ function patch (fs) {

return go$readFile(path, options, cb)

function go$readFile (path, options, cb) {
function go$readFile (path, options, cb, attempts = 0) {

This comment has been minimized.

Copy link
@ljharb

ljharb Aug 5, 2021

this breaks node <= 4, which graceful-fs 4 works on.

also this line doesn't seem to be in the PR - was it added as part of the merge?

return fs$readFile(path, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$readFile, [path, options, cb]])
enqueue([go$readFile, [path, options, cb], attempts + 1, err])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
retry()
}
})
}
Expand All @@ -135,14 +134,13 @@ function patch (fs) {

return go$writeFile(path, data, options, cb)

function go$writeFile (path, data, options, cb) {
function go$writeFile (path, data, options, cb, attempts = 0) {
return fs$writeFile(path, data, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$writeFile, [path, data, options, cb]])
enqueue([go$writeFile, [path, data, options, cb], attempts + 1, err])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
retry()
}
})
}
Expand All @@ -157,14 +155,13 @@ function patch (fs) {

return go$appendFile(path, data, options, cb)

function go$appendFile (path, data, options, cb) {
function go$appendFile (path, data, options, cb, attempts = 0) {
return fs$appendFile(path, data, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$appendFile, [path, data, options, cb]])
enqueue([go$appendFile, [path, data, options, cb], attempts + 1, err])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
retry()
}
})
}
Expand All @@ -180,14 +177,13 @@ function patch (fs) {
}
return go$copyFile(src, dest, flags, cb)

function go$copyFile (src, dest, flags, cb) {
function go$copyFile (src, dest, flags, cb, attempts = 0) {
return fs$copyFile(src, dest, flags, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$copyFile, [src, dest, flags, cb]])
enqueue([go$copyFile, [src, dest, flags, cb], attempts + 1, err])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
retry()
}
})
}
Expand All @@ -201,10 +197,10 @@ function patch (fs) {

return go$readdir(path, options, cb)

function go$readdir (path, options, cb) {
function go$readdir (path, options, cb, attempts = 0) {
return fs$readdir(path, options, function (err, files) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$readdir, [path, options, cb]])
enqueue([go$readdir, [path, options, cb], attempts + 1, err])
else {
if (files && files.sort)
files.sort()
Expand Down Expand Up @@ -338,14 +334,13 @@ function patch (fs) {

return go$open(path, flags, mode, cb)

function go$open (path, flags, mode, cb) {
function go$open (path, flags, mode, cb, attempts = 0) {
return fs$open(path, flags, mode, function (err, fd) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$open, [path, flags, mode, cb]])
enqueue([go$open, [path, flags, mode, cb], attempts + 1, err])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
retry()
}
})
}
Expand All @@ -357,12 +352,24 @@ function patch (fs) {
function enqueue (elem) {
debug('ENQUEUE', elem[0].name, elem[1])
fs[gracefulQueue].push(elem)
retry()
}

function retry () {
if (fs[gracefulQueue].length === 0)
return

var elem = fs[gracefulQueue].shift()
if (elem) {
debug('RETRY', elem[0].name, elem[1])
elem[0].apply(null, elem[1])
const [fn, args, attempts, err] = elem
if (attempts < 10) {
debug('RETRY', fn.name, args, `ATTEMPT #${attempts}`)
fn.call(null, ...args, attempts)
} else {
const cb = args.pop()
if (typeof cb === 'function')
cb.call(null, err)
}
}
setImmediate(retry)
}
2 changes: 1 addition & 1 deletion test/readdir-sort.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var fs = require("fs")

var readdir = fs.readdir
fs.readdir = function(path, cb) {
fs.readdir = function(path, options, cb) {
process.nextTick(function() {
cb(null, ["b", "z", "a"])
})
Expand Down
23 changes: 23 additions & 0 deletions test/retry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict'

var importFresh = require('import-fresh')
var path = require('path')
var realFs = require('fs')
var test = require('tap').test

var EMFILE = Object.assign(new Error('FAKE EMFILE'), { code: 'EMFILE' })

test('retries 10 times before erroring', function (t) {
var attempts = 0
realFs.readFile = function (path, options, cb) {
++attempts
process.nextTick(cb, EMFILE)
}
var fs = importFresh(path.dirname(__dirname))

fs.readFile('literally anything', function (err) {
t.equal(err.code, 'EMFILE', 'eventually got the EMFILE')
t.equal(attempts, 10, 'tried 10 times')
t.done()
})
})

0 comments on commit e4ee5d6

Please sign in to comment.