Skip to content

Watcher should ignore files not in sources before cancelling any running tasks.#2743

Open
trulede wants to merge 2 commits intogo-task:mainfrom
trulede:PR/watch-new-files
Open

Watcher should ignore files not in sources before cancelling any running tasks.#2743
trulede wants to merge 2 commits intogo-task:mainfrom
trulede:PR/watch-new-files

Conversation

@trulede
Copy link
Copy Markdown
Contributor

@trulede trulede commented Mar 15, 2026

Fix several issues with the watcher:

  • the watcher would cancel running tasks before evaluating the watch condition and, if the skip condition existed, not even restart the cancelled tasks.
  • events not being watched would cause running tasks to be cancelled (same root cause as above).
  • a watched dir that was deleted and then recreated would no longer be watched.
  • a new dir created, which should be watched, may not actually be watched.

Additional tests are added to cover most normal conditions.

Comment thread watch.go Outdated
@mkeeler
Copy link
Copy Markdown

mkeeler commented Mar 16, 2026

@trulede Feel free to bring the tests over here if you like. What about the second half to my original PR to fix the task fingerprinting uniqueness issue? Should I refactor my PR to only have that fix within it.

@trulede
Copy link
Copy Markdown
Contributor Author

trulede commented Mar 16, 2026

@mkeeler I've copied over the watch_tests and will get them running and then update this PR.

Yes, refactor your PR to have the fix for the checksums.

Co-authored-by: Oleg Butuzov <butuzov@made.ua>
Co-authored-by: Timothy Rule <34501912+trulede@users.noreply.github.com>
@trulede trulede force-pushed the PR/watch-new-files branch from 208fe5f to d65f329 Compare March 16, 2026 22:05
@trulede trulede marked this pull request as ready for review March 16, 2026 22:17
@trulede trulede added area: watcher Changes related to the Taskfile watcher. state: reviewed labels Mar 16, 2026
@trulede trulede mentioned this pull request Mar 16, 2026
@trulede trulede changed the title Watcher does not ignore created files that do not match sources. Watcher should ignore files not in sources before cancelling any running tasks. Mar 16, 2026
@mkeeler
Copy link
Copy Markdown

mkeeler commented Apr 16, 2026

@trulede Is there any reason this cannot be merged (and #2740 too)

@trulede
Copy link
Copy Markdown
Contributor Author

trulede commented Apr 16, 2026

I think @andreynering plans to merge this one soon.

@vmaerten vmaerten self-requested a review April 20, 2026 20:30
Copy link
Copy Markdown
Member

@vmaerten vmaerten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR !

In some cases the watch does not work as intended.

Considering this Taskfile :

version: '3'
tasks:
  default:
    sources:
      - "**/*.txt"
    cmds:
      - echo "Task running!"

And those steps to reproduce :

echo initial > a.txt
/tmp/task-repro --watch --verbose > /tmp/repro-watch.log 2>&1 &
sleep 1
echo updated-1 > a.txt
sleep 1
mkdir newdir && echo hello > newdir/new.txt
sleep 2
echo probe > a.txt
sleep 3

Observed output

cat /tmp/repro-watch.log

  task: Started watching for tasks: default
  task: [default] echo "Task running!"
  task: watching new dir: .
  Task running!
  task: task "default" finished running
  task: received watch event: WRITE         "/tmp/repro-watch/a.txt"
  task: [default] echo "Task running!"
  Task running!
  task: task "default" finished running
  task: received watch event: CREATE        "/tmp/repro-watch/newdir"
  task: watching new dir: newdir
  # here you should see an event for the write to a.txt but nothing appear

If I run it with main :

  task: Started watching for tasks: default
  task: watching new dir: .
  task: "default" started
  task: [default] echo "Task running!"
  Task running!
  task: "default" finished
  task: task "default" finished running
  task: received watch event: WRITE         "/tmp/repro-watch2/a.txt"
  task: "default" started
  task: [default] echo "Task running!"
  Task running!
  task: "default" finished
  task: task "default" finished running
  task: received watch event: CREATE        "/tmp/repro-watch2/newdir"
  task: skipped for file not in sources: newdir
  task: received watch event: WRITE         "/tmp/repro-watch2/a.txt"
  task: "default" started
  task: [default] echo "Task running!"
  Task running!
  task: "default" finished
  task: task "default" finished running
  task: watching new dir: newdir

@trulede
Copy link
Copy Markdown
Contributor Author

trulede commented Apr 21, 2026

That is a race condition in the underlying watcher (I believe). Its been there for a while.

The directory and file are created close together, such that the directory is not added until after the file WRITE event of the file. Therefore it is missed. There is currently a go routine, which runs on an interval, and rebuilds/rescans the watcher and picks up these new directories. So, after a period of time, the watcher should trigger on the new directory (and its contained files).

That code pre-existed this PR. However, this PR does improve the rescan algorithm so that deleted and recreated directories are correctly handled. Previously, a deleted directory handle in the watcher would become stale, and recreated directories would never trigger watch events.

The race condition might be solved in a subsequent PR, after refactoring out of some duplicated code. However its also possible that the existing periodic rescan is actually the only solution. It depends somewhat on the order that watcher events are raised (the order not always what you think).

@trulede trulede requested a review from vmaerten April 21, 2026 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: watcher Changes related to the Taskfile watcher.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

watch issue Watch hijacking dependency process

3 participants