Skip to content
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

Without tmp.setGracefulCleanup(), empty directories are not removed automatically when process exits #194

Closed
simonbrent opened this issue May 14, 2019 · 12 comments
Assignees

Comments

@simonbrent
Copy link

Operating System

Linux

NodeJS Version

10.11.0

Tmp Version

0.1.0

Expected Behavior

Empty directories created with tmp.dir are removed when the process exits

Experienced Behavior

Empty directories created with tmp.dir remain when the process exits

Code to demonstrate

const tmp = require('tmp');

const tmpDir = tmp.dir((err, path) => {
  console.log(err, path);
  process.exit();
});
const tmp = require('tmp');

const tmpDir = tmp.dirSync();
console.log(tmpDir.name);
process.exit();

In the above cases, once the process exits, ls [temp dir path] shows that the directory still exists, and is empty.

If I add tmp.setGracefulCleanup(); to the above examples, the directory is gone once the process exits.

@silkentrance
Copy link
Collaborator

silkentrance commented May 14, 2019

@simonbrent this is by design. if graceful cleanup was not called, then the garbage collector will refrain from removing any temporary objects from the filesystem.

the main reason for this is so that you can view review your temporary files after your program exists. normally, you will want to enable graceful cleanup.

of course, one could argue that this should be the default behaviour, but changing it now might break existing software, which of course will always enable graceful cleanup...

so let me think whether we can keep the setter and extend it so that one can pass a boolean which will then turn on/off the default.

@silkentrance
Copy link
Collaborator

I will prepare a PR for this right away.

silkentrance added a commit that referenced this issue May 14, 2019
@silkentrance silkentrance self-assigned this May 14, 2019
@silkentrance
Copy link
Collaborator

See PR #195

@silkentrance
Copy link
Collaborator

The rationale behind this is that under normal operation, users of tmp will always call setGracefulCleanup so that on process exit, the temporary files and empty directories will be removed from the temporary storage.

That being said, we can always also make this the default behaviour, and, in order to not break existing integrations, i.e. if someone calls setGracefulCleanup() without any parameter, the behaviour should be the same as before.

Calling setGracefulCleanup(false) will now disable that behaviour, similar to what it was before without setGracefulCleanup() being called at all.

If at all, this will only break a few fringe usages of tmp, and I think that we can live with that.

silkentrance added a commit that referenced this issue May 14, 2019
@simonbrent
Copy link
Author

@silkentrance Thanks for the response.

In light of this explanation, I think my issue is really with the documentation (and my reading of it), rather than the behaviour of the library itself.

The README states for directory creation "Simple temporary directory creation, it will be removed on process exit", and the example code does not contain setGracefulCleanup (the same is true for the file creation section). I followed this example and removed the manual cleanup line, and was then surprised when the directory was not removed on process exit.

The discussion of setGracefulCleanup is right at the bottom of the README, and only talks about needing it to remove files/directories in the case of uncaught exceptions. Since you have pointed out that setGracefulCleanup must be called to get the directory removed in my example code, even though there are no uncaught exceptions, this documentation is misleading.

I think simply fixing these issues in the README would go a long way towards helping others avoid the confusion I suffered, without any need to change the behaviour of the code :-)

@silkentrance
Copy link
Collaborator

@simonbrent Yes, the documentation lacks a little bit in this regard. However, I do think that making this the default behaviour is actually a good think; who would want a bunch of temporary files and empty folders lying around after the process terminated?

We will have to wait and see what @raszi thinks about this. If he is fine with just the addition to the README.md then we can make this happen as well.

@simonbrent simonbrent changed the title Without tmp.setGracefulCleanup(), empty directories are not removed automatically when process exist Without tmp.setGracefulCleanup(), empty directories are not removed automatically when process exits May 21, 2019
@raszi
Copy link
Owner

raszi commented Jun 4, 2019

Actually I was thinking of completely removing this feature. This causes more harm and headache than any good.

We could provide a function what can be called and what would remove the leftover files, but let's not try to capture any kind of event.

@silkentrance
Copy link
Collaborator

@raszi there is no event involved in here except for the exit handler, which now, by default, will remove all stale tmp files and directories, even if they have been populated.

and if the user wants to keep the populated (or empty) directories, then he must call setGracefulCleanup(false).

@raszi
Copy link
Owner

raszi commented Jun 7, 2019

I am talking about this part:

https://github.com/raszi/node-tmp/blob/master/lib/tmp.js#L602-L678

@joma74
Copy link

joma74 commented Jun 14, 2019

To chime in, consider the following case

import onExit from  "async-exit-hook"
...
this.profileDir = tmp.dirSync({
      dir: TESTCAFE_EXT_TMP_DIRS_ROOT,
      prefix: namePrefix + "-",
      keep: false,
      unsafeCleanup: true,
    })
onExit(this.profileDir.removeCallback)

As of tmp@0.1.0, observed that when hooking in that async exit handler to tmp's 'removeCallback', the dirs are not removed. Deeper cause is that tmp's callback triggers a rimraf function that in turn calls node's async fs.lstat with a callback that never runs. Hmm, maybe a local problem. See also https://github.com/tapppi/async-exit-hook#considerations-and-warning for caveats.

So i opted for

tmp.setGracefulCleanup()
...
this.profileDir = tmp.dirSync({
      dir: TESTCAFE_EXT_TMP_DIRS_ROOT,
      prefix: namePrefix + "-",
      keep: false,
      unsafeCleanup: true,
    })

and all dirs were deleted. Difference is that on 'tmp.setGracefulCleanup()', tmp calls _rimrafRemoveDirSyncWrapper directly, which, by using node's sync fs.lstatSync, works.

Point is that i feel that users should have an option to decide if they want a sync version of tmp's 'removeCallback'. Even more if you ever decide to remove setGracefulCleanup with it's exit listeners.

@silkentrance
Copy link
Collaborator

@joma74 that is exactly why, under the hood, tmp uses rimraf synchronously, especially in its exit and sigint handlers.

as for user callbacks and the cleanup callbacks passed to them, they have always been async, even in the past, so there was no change to that behaviour.

@silkentrance
Copy link
Collaborator

silkentrance commented Jan 27, 2020

This should have been fixed with commit 9438539#diff-4f99eaef47493ba13b06879592d2a1c4R501.
node introduced a second option to rmdirSync. In the past we just passed the optional next callback handler, relying on rmdirSync to just ignore any additional parameters.
The same behaviour is now on master which incorporates the bug fix for #197.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants