Filesystem-change-evt triggers twice

#lang racket

(require racket/runtime-path)

(define-runtime-path here ".")
(define the-path (build-path here "touchme.txt"))

(let loop ()
  (displayln "starting the loop...")

  (sync (filesystem-change-evt the-path))
  (displayln "file changed")
  (loop))

This is triggering twice on a given change and I'm confused as to why.

The exact sequence goes:

  1. Run the code
  2. It displays "starting the loop..." as expected
  3. From the command line, touch touchme.txt
  4. It displays "file changed" as expected
  5. It displays "starting the loop" as expected
  6. It displays "file changed" !! What??

Putting a (sleep 1) after the displayln does not fix the issue, but (sleep 2) does, which leads me to believe that the issue is a dirty cache of the modified timestamp.

Is this a bug or is this another case of "operating systems be bad, yo"?

I'm running on macOS 10.15.5 (19F101) using Racket 8.4.

1 Like

I'm on MacOS 10.15.7 (19H1715) with Racket 8.4 [cs] and on each touch it is only displaying "file changed" once.

2 Likes

Based on past experiences --- unfortunately I can't recall exactly, and it may have applied only in some older versions of Racket --- I tend to take the filesystem change notifications with a grain of salt.

If there's some condition I'm interested in, I don't take the readiness as a guarantee the condition is true. I just take it as a suggestion it's a good time to check the condition again, myself.

That might be unnecessarily conservative, though.

The docs do mention:

Finally, depending on the precision of information available from the operating system, the event may become ready for synchronization under other circumstances. For example, on Windows, an event for a file becomes ready when any file changes within in the same directory as the file.

That example isn't yours (it's about precision of file system "scope" not precision of time), but the docs imply there could be more examples now or in the future, I think?

So even if your specific example is in fact a bug or limitation in Racket, and even if it is fixed or changed, it might be good to treat the change notifications a little defensively/skeptically.

7 Likes