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

Restart not firing beyond deletion of directory under watch, when this directory structure is recreated (on Ubuntu 22.04) #2192

Open
morgaan opened this issue Mar 27, 2024 · 11 comments
Labels
stale no activity for 2 weeks

Comments

@morgaan
Copy link

morgaan commented Mar 27, 2024

  • Versions: node@v18.17.1, linux@6.5.0-25-generic
  • nodemon -v: 3.1.0
  • Operating system/terminal environment (powershell, gitshell, etc): Ubuntu 22.04
  • Using Docker? No
  • Command you ran: nodemon app.js

Expected behaviour

On Linux, when nodemon is configured to watch for an assets/ directory, and that assets/ exists when the nodemon command is executed; if assets/ is deleted and then later on recreated and/or has changes happening inside it; nodemon should restart and the restart event hook should be executed.

Actual behaviour

Upon assets/ deletion, nodemon does restart, but that is the end of it. Indeed when the assets/ directory gets recreated and moreover has changes happening inside it, nodemon does ignore it all. Just as if assets/ has been dropped from the watch list.

It is worth noting, that under MacOs, it works as described in the Expected behaviour.

Steps to reproduce

  1. In a fresh new directory: run npm init -y
  2. Install nodemon: run npm install -D nodemon@3.1.0
  3. Create the assets/ directory and file: run mkdir assets && echo "I'm an asset" > file.txt
  4. Create the app.js file: echo "console.log('Hello World!');" > app.js
  5. Amend package.json file to contain following nodemonConfig root property:
  "nodemonConfig": {
    "watch": [
      "assets/",
      "app.js"
    ],
      "ext": "*.*",
      "delay": 1,
      "events": {
        "restart": "echo 'restarting'"
      }
  }
  1. Start app.js with nodemon: Run npx nodemon app.js
  2. In an another Terminal window/tab, and in the directory that host the application, delete the assets/ directory: Run rm -rf assets
  3. Coming back to the Terminal window/tab that runs nodemon, you should see nodemon restarting due to changes and logging restarting followed by Hello World!, so far, all good!
  4. Now again in the other Terminal window/tab, recreate the asset assets/file.txt: Run mkdir assets && echo "I'm an asset" > file.txt
  5. Coming back to the Terminal window/tab that runs nodemon, you won't see any new nodemon restart. That is the issue I'm raising
  6. Bonus: Again in the other Terminal window/tab, make a change to app.js: Run echo "console.log('Still running!');" >> app.js
  7. Coming back to the Terminal window/tab that runs nodemon, you should see nodemon restarting due to app.js changes and logging restarting followed by Hello World! followed by Still running!. So the watch is still working but only for resources that have not been deleted.

Here is the `--dump`
--------------
node: v18.17.1
nodemon: 3.1.0
command: /home/unicorn/.nvm/versions/node/v18.17.1/bin/node /home/unicorn/nodemon-issue-sandbox/node_modules/.bin/nodemon --dump
cwd: /home/unicorn/nodemon-issue-sandbox
OS: linux x64
--------------
{
  run: false,
  system: { cwd: '/home/unicorn/nodemon-issue-sandbox' },
  required: false,
  dirs: [
    '/home/unicorn/nodemon-issue-sandbox/assets',
    '/home/unicorn/nodemon-issue-sandbox/app.js'
  ],
  timeout: 1000,
  options: {
    dump: true,
    watch: [ 'assets/', 'app.js', re: /assets\/|app\.js/ ],
    delay: 1,
    events: { restart: "echo 'restarting'" },
    ignore: [
      '**/.git/**',
      '**/.nyc_output/**',
      '**/.sass-cache/**',
      '**/bower_components/**',
      '**/coverage/**',
      '**/node_modules/**',
      re: /.*.*\/\.git\/.*.*|.*.*\/\.nyc_output\/.*.*|.*.*\/\.sass\-cache\/.*.*|.*.*\/bower_components\/.*.*|.*.*\/coverage\/.*.*|.*.*\/node_modules\/.*.*/
    ],
    monitor: [
      '/home/unicorn/nodemon-issue-sandbox/assets/**/*',
      'app.js',
      '!**/.git/**',
      '!**/.nyc_output/**',
      '!**/.sass-cache/**',
      '!**/bower_components/**',
      '!**/coverage/**',
      '!**/node_modules/**'
    ],
    ignoreRoot: [
      '**/.git/**',
      '**/.nyc_output/**',
      '**/.sass-cache/**',
      '**/bower_components/**',
      '**/coverage/**',
      '**/node_modules/**'
    ],
    restartable: 'rs',
    colours: true,
    execMap: { py: 'python', rb: 'ruby', ts: 'ts-node' },
    stdin: true,
    runOnChangeOnly: false,
    verbose: false,
    signal: 'SIGUSR2',
    stdout: true,
    watchOptions: {},
    execOptions: {
      script: 'index.js',
      exec: 'node',
      args: [],
      scriptPosition: 0,
      nodeArgs: undefined,
      execArgs: [],
      ext: '',
      env: {}
    }
  },
  load: [Function (anonymous)],
  reset: [Function: reset],
  lastStarted: 0,
  loaded: [ '/home/unicorn/nodemon-issue-sandbox/package.json' ],
  watchInterval: null,
  signal: 'SIGUSR2',
  command: {
    raw: { executable: 'node', args: [ 'index.js' ] },
    string: 'node index.js'
  }
}
 
Copy link

This issue has been automatically marked as idle and stale because it hasn't had any recent activity. It will be automtically closed if no further activity occurs. If you think this is wrong, or the problem still persists, just pop a reply in the comments and @remy will (try!) to follow up.
Thank you for contributing <3

@github-actions github-actions bot added the stale no activity for 2 weeks label Apr 10, 2024
@morgaan
Copy link
Author

morgaan commented Apr 16, 2024

I'm convinced this requires attention! I would be very thankful if you could give it a look 🙏

@github-actions github-actions bot removed the stale no activity for 2 weeks label Apr 16, 2024
@ryanto
Copy link

ryanto commented Apr 22, 2024

Just want to confirm I'm seeing this behavior on Windows 11 as well. After a watched directory is deleted (and recreated) nodemon stops picking up changes. Tested on nodemon 3.1.0.

Fwiw I'm only seeing this issue on Windows, on macOS everything works as expected.

PS: Thanks so much for nodemon, it's a real time saver while developing!

@brainthinks
Copy link

I am also running into this. My use case is that my build process (for typescript) runs rm -rf ./dist, which is the dir that nodemon is watching. I ended up rolling my own file watcher...

Posting here in case anyone finds it useful. Note that this is specific to my use case, so YMMV.

#!/usr/bin/env node

/**
 * @see https://github.com/remy/nodemon?tab=readme-ov-file#using-nodemon-as-a-module
 * @see https://github.com/remy/nodemon/blob/main/doc/requireable.md
 */

import fs from 'node:fs';

import debounce from 'lodash-es/debounce.js';

import utils from 'nodemon/lib/utils/index.js';
import nodemonLogger from 'nodemon/lib/utils/log.js';
import nodemon from 'nodemon';

// @see https://github.com/remy/nodemon/issues/2195
utils.log = nodemonLogger(false);

// @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/nodemon/index.d.ts
const config = {
  verbose: true,
  watch: [ './dist' ],
  delay: 2000,
  exec: 'yarn run serve:dev',
  runOnChangeOnly: true,
};

nodemon(config);

// Don't accidentally spam nodemon.restart
const nodemonRestart = debounce(() => { nodemon.restart(); }, 2_000);

for (let i = 0; i < config.watch.length; i++) {
  const watchEntry = config.watch[i];

  // NOTE - `nodemon`, `chokidar`, `onchange`, `fs.watch` etc. don't work for
  // at least one of the following 2 reasons:
  //
  //   1. inability to respond to directory deletetions
  //   2. no options for polling, needed for Docker volumes
  //
  // Therefore, we roll our own file watcher with `fs.watchFile`, which works
  // in all tested scenarios.
  fs.watchFile(
    watchEntry,
    { persistent: true, interval: 500 },
    (curr, prev) => {
      if (curr.mtimeMs > prev.mtimeMs) {
        utils.log.info(`WATCHER: ${watchEntry} was deleted then recreated...`);
        nodemonRestart();
      }
    },
  );
}

utils.log.status('Watching for changes...');

@remy
Copy link
Owner

remy commented Apr 23, 2024

Just adding a thought but if you're directly watching "assets" and it's deleted then later recreated, I'm not sure why it would work.

This is because the watcher is explicitly registering the directory, so once it's gone it has nothing to hook.

This is because nodemon isn't arbitrarily watching for all changes.

If you were watching the parent directory, then I'd expect there to be a way to register deletion and recreation.

@ryanto
Copy link

ryanto commented Apr 23, 2024

Makes sense... surprisingly it works on macOS which I think is what threw me off.

In my situation the parent directory has a lot of files that change often, but I'm only interested a single sub directory (the one that's being deleted and re-created). In that case do you think it's best to watch the parent directory and then ignore everything in the parent that I'm not interested in?

Thanks in advance!

@morgaan
Copy link
Author

morgaan commented Apr 23, 2024

Thank you @remy, I can only double what @ryanto wrote. Looking forward to your next comment 🍿

@brainthinks
Copy link

@remy to address your comment, under "normal" circumstances, you are correct in that watching a deleted folder will not work, for the reasons you mention. I think the sentiment in this issue is that this is a desirable feature, though it isn't something that is supported by the underlying file-watching libraries / logic.

I tried messing around with the watch and ignore values, and seemed to get close, since the changes triggered nodemon's watch monitor, but ultimately I think this is a limitation of chokidar. I'm not sure that nodemon could support this use case without adding an alternative watch implementation based on node's fs.watchFile, or something that was similarly tolerant to deletions and recreations. This is definitely non-trivial, as there is also a lot of supporting code around the chokidar watcher, and would likely require a different strategy for managing the watchers...

As such, I don't think nodemon can support this use case without significant effort, hence why I wrote my own watch for my dist directory.

My intention with this post is to hopefully answer the question of "why doesn't this work" and assert that it can't work without significant effort, which would involve either rewriting the watcher logic or writing an entire alternative based on something other than chokidar.

@remy
Copy link
Owner

remy commented Apr 23, 2024

@brainthinks to be honest, I think raising it with the chokidar repo might be the sensible direction. I'm really not sure where it lands in terms of desire to support, but the fact you've got inconsistent behaviour between windows and macros suggests there's favour for fixing/adding it to chokidar.

@morgaan
Copy link
Author

morgaan commented Apr 25, 2024

@brainthinks Sorry I had missed your initial message with the code snippet 😊.
I believe it can be super handy for folks, so thank you so much for sharing.

On my end, as we actually revisited our approach to avoid getting in the situation of having the directory deleted while nodemon is watching it, we seem to be out of trouble and therefore do not need the snippet nor this fix. But if in some other constellation I find myself stuck in this situation, and this has not been addressed, most likely at chokidar level, I'll know where to look for so thank you again.

Thank you all

Copy link

github-actions bot commented May 9, 2024

This issue has been automatically marked as idle and stale because it hasn't had any recent activity. It will be automtically closed if no further activity occurs. If you think this is wrong, or the problem still persists, just pop a reply in the comments and @remy will (try!) to follow up.
Thank you for contributing <3

@github-actions github-actions bot added the stale no activity for 2 weeks label May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale no activity for 2 weeks
Projects
None yet
Development

No branches or pull requests

4 participants