I am using BetterFileWatching.jl and the following code snippet:
watch_task = @async watch_folder(".") do event
@info "Something changed!" event
end
sleep(5)
# stop watching the folder
schedule(watch_task, InterruptException(); error=true)
The task runs fine, but the schedule to stop it never works. I assume the authors have had success with this expression in past julia versions (since they wrote it works), but for 1.8 this does not work anymore in my case. Is this a regression or is there another way to stop the task?
Can you specify what you see? In my case, with both Julia 1.7 and 1.8, running the schedule line produces Task (done) @ followed by the hexadecimal task id.
You could also try running !istaskdone(watch_task) && yield(watch_task) after the schedule to explicitly yield to the watch_task in case it’s not picked up by the scheduler for some reason.
Yes it indeed produces “Task done + hex id” here as well, but it keeps outputting changes in the directory after the task supposedly has been stopped. This is of course incorrect behaviour. Running your snippet piece by piece:
!istaskdone(watch_task)
false
Which indicates that the scheduler is not picking it up. The yield command produces:
The error seems to happen in the “do” statement. The task will be “done” since it runs through the code, but the “do” statement, never experiences “closure”.
Honestly this seems like it might be a library problem i.e. a bug as you’ve mentioned in your issue.
The watch_folder code creates its own inner Task with @async, and any exception on that is handled by passing an InterruptException to the Deno task which should end the file watching. However, the InterruptException we pass in the code from the README is never passed on to this inner task, so this never happens. (Basically, there’s three layers of Tasks, and we’re able to pass an Interrupt only to the outer layer, which doesn’t get propagated to the inner two.) This is all based on my so-so understanding of Tasks though, so I’ve subscribed to the Issue on Github to see what the update is going to be.
For now, it seems like the library is pretty young and not highly used (only 3 stars on the project), so you’re probably better off using the FileWatching standard library.
I tried using the standard library file watching, but I simply couldn’t get it to work asynchrounosly. I would risk that if for example 4 files are created at once, then only one of them is registered - this is suboptimal.
Do you happen to know how one could write an async version doing the same thing, but without this bug?
I tried to do the straight forward, swapping “watch_folder” function to the standard library, but it simply would not accept the do syntax, which seems necessary for this async behaviour.
The problem is now that I don’t understand what is “changed”, “renamed” and “timeout” actually means in the “FileEvent” result.
Renamed and timeout should just be change of name and “fail if taken too long”, but I cannot figure out how to split “changed” into “created” and “modified” which BetterFileWatching.jl does really smartly and intuitively. I am almost there, so I hope someone perhaps understands this part better.
Still surprised that something I thought would be so easy to do is actually the most difficult part to code up…
For me renamed was set both for renamed files as well as newly created files. timeout refers to whether an optional argument to watch_folder was exceeded. You don’t need the construct sleep...schedule(..;error).
You are indeed right that renaming = new file, even though it annoys me not being able to discern between modified name and actual new file. Still for now it is workable for me.
Thank you for your help and time - it lets me progress my general code now.
I do hope though that this becomes much better, because I find it so unbelievable that a language as Julia, which is good at so many things, actually struggles to properly close down subtasks and perform IO operations - thankfully you gave me the quick workaround, which is why I marked your answer as solution.