-
Notifications
You must be signed in to change notification settings - Fork 775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix removeSync() to eliminate spurious ENOTEMPTY errors on Windows #646
Conversation
standard: Use JavaScript Standard Style (https://standardjs.com) standard: Run `standard --fix` to automatically fix some problems. /home/travis/build/jprichardson/node-fs-extra/lib/remove/rimraf.js:300:33: Extra semicolon. /home/travis/build/jprichardson/node-fs-extra/lib/remove/rimraf.js:302:42: Extra semicolon. /home/travis/build/jprichardson/node-fs-extra/lib/remove/rimraf.js:309:5: Block must not be padded by blank lines ```
ad9e9de
to
ccd7d34
Compare
@RyanZim @manidlou One of the CI jobs is failing with this error?
This seems unrelated to my change. Any idea what it means? |
Yeah, linter isn't working right. |
@RyanZim what's the expected turnaround time for merging PRs? This issue is currently a nuisance for many people. If it will take a while, we can try to find another solution for deleting the folders in the meantime. |
Does |
@RyanZim hmmm... Its heuristic does measure clock time, but in a strange way that also counts the time spent iterating the loop: function rimraf (p, options, cb) {
let busyTries = 0
if (typeof options === 'function') {
cb = options
options = {}
}
assert(p, 'rimraf: missing path')
assert.strictEqual(typeof p, 'string', 'rimraf: path should be a string')
assert.strictEqual(typeof cb, 'function', 'rimraf: callback function required')
assert(options, 'rimraf: invalid options argument provided')
assert.strictEqual(typeof options, 'object', 'rimraf: options should be object')
defaults(options)
rimraf_(p, options, function CB (er) {
if (er) {
if ((er.code === 'EBUSY' || er.code === 'ENOTEMPTY' || er.code === 'EPERM') &&
busyTries < options.maxBusyTries) {
busyTries++
const time = busyTries * 100
// try again, with the same exact callback as this one.
return setTimeout(() => rimraf_(p, options, CB), time)
}
// already gone
if (er.code === 'ENOENT') er = null
}
cb(er)
})
} Ideally it should be improved to use the same measurement strategy and time limit constant as removeSync(). However, my projects generally avoid NodeJS's async APIs for performance reasons. So if I fix that one, I don't have a real world project handy to test the PR. That said, I'd be willing to make that fix. But it may take me a few days to get some time. Since the original issue is causing a real problem, and people are pestering me for a fix, would you be okay with merging this PR, and handling that issue as a separate PR? |
I'd prefer to keep sync and async methods in lockstep together. |
@pgonzal mentioned that file handles usually take 100ms to 200ms to close. In its default configuration, the async For a symmetrical change to happen to the async function, I think we'd have to make an actual API change to make the retry logic based on clock time instead of number of retries, which seems pretty out-of-scope for this change and unnecessary. |
OK, merging by itself. |
Published in 7.0.1 |
@RyanZim thanks! How do you feel about changing the API for the async |
Since there's an existing option for this, I'd say we leave it as it is for now. |
…EMPTY: directory not empty, rmdir" for FileSystem.deleteFolder() See jprichardson/node-fs-extra#646
Summary: Changes are mostly bug fixes, that shouldn't affect us. From the change log: 7.0.1 / 2018-11-07 ------------------ - Fix `removeSync()` on Windows, in some cases, it would error out with `ENOTEMPTY` ([#646](jprichardson/node-fs-extra#646)) - Document `mode` option for `ensureDir*()` ([#587](jprichardson/node-fs-extra#587)) - Don't include documentation files in npm package tarball ([#642](jprichardson/node-fs-extra#642), [#643](jprichardson/node-fs-extra#643)) 7.0.0 / 2018-07-16 ------------------ - **BREAKING:** Refine `copy*()` handling of symlinks to properly detect symlinks that point to the same file. ([#582](jprichardson/node-fs-extra#582)) - Fix bug with copying write-protected directories ([#600](jprichardson/node-fs-extra#600)) - Universalify `fs.lchmod()` ([#596](jprichardson/node-fs-extra#596)) - Add `engines` field to `package.json` ([#580](jprichardson/node-fs-extra#580)) 6.0.1 / 2018-05-09 ------------------ - Fix `fs.promises` `ExperimentalWarning` on Node v10.1.0 ([#578](jprichardson/node-fs-extra#578)) 6.0.0 / 2018-05-01 ------------------ - Drop support for Node.js versions 4, 5, & 7 ([#564](jprichardson/node-fs-extra#564)) - Rewrite `move` to use `fs.rename` where possible ([#549](jprichardson/node-fs-extra#549)) - Don't convert relative paths to absolute paths for `filter` ([#554](jprichardson/node-fs-extra#554)) - `copy*`'s behavior when `preserveTimestamps` is `false` has been OS-dependent since 5.0.0, but that's now explicitly noted in the docs ([#563](jprichardson/node-fs-extra#563)) - Fix subdirectory detection for `copy*` & `move*` ([#541](jprichardson/node-fs-extra#541)) - Handle case-insensitive paths correctly in `copy*` ([#568](jprichardson/node-fs-extra#568)) Reviewed By: jknoxville Differential Revision: D13023753 fbshipit-source-id: 1ecc6f40be4c8146f92dd29ede846b5ab56765ea
Running into this issue with unit test cleanup on fs-extra v9.0.0. Is there any workaround for this problem? I don't think it is just a timing issue because I am able to set a breakpoint just prior to calling |
Is it possible that the unit test code has a race condition? For example, an async function that is suspended while you are stopped in the debugger? The behavior you described sounds like it might be a problem with the calling code, not with To eliminate that concern, you could try to make a small isolated script that reproduces the bug without relying on any test frameworks. I can attest that |
If you get a reduced test case, please open a new issue about it, instead of commenting on this old thread. Thanks! |
Lately I've been seeing a lot of errors like this on Windows:
The Windows OS prevents a folder from being removed while file handles are still open. Certain processes such as virus scanners and compiler environments watch folders for changes. After a folder is removed, they take a little while to realize this and unregister their handlers. In my empirical tests, it can occasionally take around 100ms - 200ms.
fs-extra already provides some protection against this:
rimraf.js
However, this algorithm relies on a retry count to decide when to give up. If the PC is idle or has very fast hardware, then 100 retries is way too little. We could increase the limit, but the units are arbitrary.
This PR changes the loop to measure actual time, since that's more representative of the underlying problem.