Skip to content

Add DirectoryListener - #764

Open
dr0i wants to merge 3 commits into
masterfrom
702-addDirectoryListener
Open

Add DirectoryListener#764
dr0i wants to merge 3 commits into
masterfrom
702-addDirectoryListener

Conversation

@dr0i

@dr0i dr0i commented Apr 14, 2026

Copy link
Copy Markdown
Member

See #702.

This PR works in principle.
Be aware that there is a bug regarding the WatchService that can result in a loss of awareness of created files, e.g. if these files are created too fast in a row, or e.g. by moving a whole directory with files in it to the directory which is listened to: that directory would be watched, but the files in there won't be recognized. So it's not as inotify in unix contexts - it only comes close to it.

You may want to test it like this:

  1. ./gradlew assembleDist (in the root of this branch to build the runner)
  2. cd ./metafacture-runner/build/distributions/
  3. tar xfz metafacture-core-702-addDirectoryListener-SNAPSHOT-dist.tar.gz
  4. create a FLUX:
echo "default infile = FLUX_DIR + 'tmp';
infile|
listen-directory|
print
;"  > directoryListener.flux
  1. mkdir tmp (creates the directory to listen to)
  2. metafacture-core-702-addDirectoryListener-SNAPSHOT-dist/flux.sh directoryListener.flux to execute the FLUX
  3. touch 1 2 3 4 5 6 7 tmp/ to create some files

You should see as output the names of the files with absolute path (which could be given in the FLUX to open-file) and some logs (which are not going to the piped flux-command (as e.g. open-file)) are printed to stdout.
(Interestingly , you see that even "touch"ing 7 files consecutively the WatchService is fast enough to observe the creation of these files.)

If you want the listener to go down: trigger it with the specially named file:
touch shutdownEtlNow

We may want to discuss if it's necessary to improve the behaviour by building some workarounds. One idea would be to just traverse the given directory every n-th second and notate the filenames, if any new appear, to a Map and push these down the pipe. This would guarantee to not miss one file (at the cost of not instantly getting the filename if one was created.)

@dr0i

dr0i commented Apr 14, 2026

Copy link
Copy Markdown
Member Author

functional review: @TobiasNx (and maybe @fsteeg as this PR is supposed to be part of a workflow in the RPB context).
discussion (re bug and workaround): also @blackwinter
code review: @blackwinter (or @fsteeg )

@dr0i
dr0i requested review from TobiasNx and fsteeg April 14, 2026 14:41
@dr0i dr0i linked an issue Apr 14, 2026 that may be closed by this pull request
@TobiasNx

TobiasNx commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

@fsteeg and I tested it. I followed your example:

default infile = FLUX_DIR + 'tmp';
infile|
listen-directory|
print
;

Your example flux with printing seems to work fine when creating or modifing files. The logging is a little too much.

tobias@hbz-hp:~/temp$ '/home/tobias/git/metafacture-core/metafacture-runner/build/install/metafacture-core/flux.sh' directoryListener.flux
Add directory to watch: /home/tobias/temp/tmp
Event kind:ENTRY_CREATE. File affected: 1.
/home/tobias/temp/tmp/1Event kind:ENTRY_MODIFY. File affected: 1.

/home/tobias/temp/tmp/1Event kind:ENTRY_CREATE. File affected: 2.

/home/tobias/temp/tmp/2Event kind:ENTRY_MODIFY. File affected: 2.

/home/tobias/temp/tmp/2Event kind:ENTRY_CREATE. File affected: 3.

/home/tobias/temp/tmp/3Event kind:ENTRY_MODIFY. File affected: 3.

/home/tobias/temp/tmp/3Event kind:ENTRY_CREATE. File affected: 4.

/home/tobias/temp/tmp/4Event kind:ENTRY_MODIFY. File affected: 4.

/home/tobias/temp/tmp/4Event kind:ENTRY_CREATE. File affected: 5.

/home/tobias/temp/tmp/5Event kind:ENTRY_MODIFY. File affected: 5.

/home/tobias/temp/tmp/5Event kind:ENTRY_CREATE. File affected: 6.

/home/tobias/temp/tmp/6Event kind:ENTRY_MODIFY. File affected: 6.

/home/tobias/temp/tmp/6Event kind:ENTRY_CREATE. File affected: 7.

/home/tobias/temp/tmp/7Event kind:ENTRY_MODIFY. File affected: 7.

/home/tobias/temp/tmp/7Event kind:ENTRY_CREATE. File affected: .1.swp.

/home/tobias/temp/tmp/.1.swpEvent kind:ENTRY_MODIFY. File affected: .1.swp.

/home/tobias/temp/tmp/.1.swpEvent kind:ENTRY_CREATE. File affected: .1.swp.

/home/tobias/temp/tmp/.1.swpEvent kind:ENTRY_MODIFY. File affected: .1.swp.

/home/tobias/temp/tmp/.1.swpEvent kind:ENTRY_MODIFY. File affected: 1.

/home/tobias/temp/tmp/1Event kind:ENTRY_CREATE. File affected: shutdownEtlNow.
Event kind:ENTRY_MODIFY. File affected: shutdownEtlNow.

When changing print to write the process closes and the flux breaks when a file is modified or created.

tobias@hbz-hp:~/temp$ '/home/tobias/git/metafacture-core/metafacture-runner/build/install/metafacture-core/flux.sh' directoryListener.flux
Add directory to watch: /home/tobias/temp/tmp
Event kind:ENTRY_CREATE. File affected: .1.swp.
Exception in thread "Thread-0" org.metafacture.framework.MetafactureException: java.io.IOException: Stream closed
	at org.metafacture.io.ObjectFileWriter.process(ObjectFileWriter.java:110)
	at org.metafacture.io.ObjectWriter.process(ObjectWriter.java:147)
	at org.metafacture.io.DirectoryListener$DirectoryWatcher.processFile(DirectoryListener.java:195)
	at org.metafacture.io.DirectoryListener$DirectoryWatcher.run(DirectoryListener.java:166)
	at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.io.IOException: Stream closed
	at java.base/sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:51)
	at java.base/sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
	at java.base/sun.nio.cs.StreamEncoder.write(StreamEncoder.java:142)
	at java.base/java.io.OutputStreamWriter.write(OutputStreamWriter.java:223)
	at java.base/java.io.Writer.write(Writer.java:249)
	at org.metafacture.io.ObjectFileWriter.process(ObjectFileWriter.java:101)
	... 4 more

What I currently also do not understand is how I am able to recognize the filenames to further process the changed or created files. What is the output of listen-directory?

@fsteeg
fsteeg removed request for TobiasNx and fsteeg April 29, 2026 13:32
@fsteeg fsteeg assigned dr0i and unassigned fsteeg and TobiasNx Apr 29, 2026
@dr0i

dr0i commented Jun 16, 2026

Copy link
Copy Markdown
Member Author

What I currently also do not understand is how I am able to recognize the filenames to further process the changed or created files. What is the output of listen-directory?

Is there something missing in the description, something unclear? Did you read it? It begins with:
"Listens to a directory and passes occurring filenames to the receiver."

When changing print to write the process closes and the flux breaks when a file is modified or created.

Did you initialize writer correctly by given a path as destination? How exactly is your flux looking like?

@dr0i
dr0i requested a review from TobiasNx June 16, 2026 08:08
@dr0i dr0i assigned TobiasNx and unassigned dr0i Jun 16, 2026
@TobiasNx

TobiasNx commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

I added my test as runner example, so that you can check this: 759ce79

By the way, if the intended directory is a file instead the listener seems also to run. I am not sure if that is intended.

Documentation is fine. +1 for this.

@TobiasNx TobiasNx assigned dr0i and unassigned TobiasNx Jun 18, 2026
@dr0i
dr0i force-pushed the 702-addDirectoryListener branch from 759ce79 to 83ffeee Compare June 18, 2026 15:20
@TobiasNx

Copy link
Copy Markdown
Contributor

@dr0i unfortunatly you forced-pushed over my commit: 759ce79

@dr0i

dr0i commented Jun 18, 2026

Copy link
Copy Markdown
Member Author

@TobiasNx can you add your test again - I've force pushed over it.

By the way, if the intended directory is a file instead the listener seems also to run.

I don't understand this. Do you mean, you create a directory and it's passed to receiver? That shouldn't happen!

- improve doc
- test removing a file
@dr0i
dr0i force-pushed the 702-addDirectoryListener branch from 83ffeee to 87f9be4 Compare June 18, 2026 15:31
@TobiasNx

Copy link
Copy Markdown
Contributor

If you use instead mkdir tmp touch tmp so that no directory but a tmp file is created. Then run the script (but with print.

@dr0i

dr0i commented Jun 18, 2026

Copy link
Copy Markdown
Member Author

If you use instead mkdir tmp touch tmp so that no directory but a tmp file is created

That's the expected behaviour - if you mean that this filename is passed. Because it is a filename, isnt' it?

@@ -0,0 +1,5 @@
default infile = FLUX_DIR + "tmp";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This path should point to a directory but it seems that it does not through an error if it points to a file instead of a directory.

I thought that this should be tmp/ and breaks if it points to a file.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

#775 this pr shows the scenario when the input is a file-path instead of an directory path

@dr0i dr0i assigned TobiasNx and unassigned dr0i Jun 18, 2026
default infile = FLUX_DIR + "tmp";
infile|
listen-directory|
write (FLUX_DIR + "result.txt")

@TobiasNx TobiasNx Jun 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would change this to print before merging. write is currently only used to highlight issue with the directory listener mentioned here: #764 (comment)

@TobiasNx TobiasNx Jun 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This example should highlight the problem with the writing that I reported mentioned here: #764 (comment)

@TobiasNx

Copy link
Copy Markdown
Contributor

That's the expected behaviour - if you mean that this filename is passed. Because it is a filename, isnt' it?

@dr0i see my inline comment and the upbranched PR #775

I would expect that if the input is a filepath instead of an directory path that an exception is thrown.

Also see my inline comment with regard to the problem when writing.

@TobiasNx

TobiasNx commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

In order to reduce the noise, I provide a structured list of all of my findings:

  1. "What is the output of listen-directory?" -> @dr0i hinted to the documentation. So this is okay. ✔️
  2. Default logging when using your example seems to be a little too much. Maybe okay:
Logging
tobias@hbz-hp:~/temp$ '/home/user/git/metafacture-core/metafacture-runner/build/install/metafacture-core/flux.sh' directoryListener.flux
Add directory to watch: /home/tobias/temp/tmp
Event kind:ENTRY_CREATE. File affected: 1.
/home/tobias/temp/tmp/1Event kind:ENTRY_MODIFY. File affected: 1.

/home/tobias/temp/tmp/1Event kind:ENTRY_CREATE. File affected: 2.

/home/tobias/temp/tmp/2Event kind:ENTRY_MODIFY. File affected: 2.

/home/tobias/temp/tmp/2Event kind:ENTRY_CREATE. File affected: 3.

/home/tobias/temp/tmp/3Event kind:ENTRY_MODIFY. File affected: 3.

/home/tobias/temp/tmp/3Event kind:ENTRY_CREATE. File affected: 4.

/home/tobias/temp/tmp/4Event kind:ENTRY_MODIFY. File affected: 4.

/home/tobias/temp/tmp/4Event kind:ENTRY_CREATE. File affected: 5.

/home/tobias/temp/tmp/5Event kind:ENTRY_MODIFY. File affected: 5.

/home/tobias/temp/tmp/5Event kind:ENTRY_CREATE. File affected: 6.

/home/tobias/temp/tmp/6Event kind:ENTRY_MODIFY. File affected: 6.

/home/tobias/temp/tmp/6Event kind:ENTRY_CREATE. File affected: 7.

/home/tobias/temp/tmp/7Event kind:ENTRY_MODIFY. File affected: 7.

/home/tobias/temp/tmp/7Event kind:ENTRY_CREATE. File affected: .1.swp.

/home/tobias/temp/tmp/.1.swpEvent kind:ENTRY_MODIFY. File affected: .1.swp.

/home/tobias/temp/tmp/.1.swpEvent kind:ENTRY_CREATE. File affected: .1.swp.

/home/tobias/temp/tmp/.1.swpEvent kind:ENTRY_MODIFY. File affected: .1.swp.

/home/tobias/temp/tmp/.1.swpEvent kind:ENTRY_MODIFY. File affected: 1.

/home/tobias/temp/tmp/1Event kind:ENTRY_CREATE. File affected: shutdownEtlNow.
Event kind:ENTRY_MODIFY. File affected: shutdownEtlNow.
  1. Using write after listen-directory breaks as in my added runner example: 759ce79
Exception

tobias@hbz-hp:~/temp$ '/home/tobias/git/metafacture-core/metafacture-runner/build/install/metafacture-core/flux.sh' directoryListener.flux
Add directory to watch: /home/tobias/temp/tmp
Event kind:ENTRY_CREATE. File affected: .1.swp.
Exception in thread "Thread-0" org.metafacture.framework.MetafactureException: java.io.IOException: Stream closed
at org.metafacture.io.ObjectFileWriter.process(ObjectFileWriter.java:110)
at org.metafacture.io.ObjectWriter.process(ObjectWriter.java:147)
at org.metafacture.io.DirectoryListener$DirectoryWatcher.processFile(DirectoryListener.java:195)
at org.metafacture.io.DirectoryListener$DirectoryWatcher.run(DirectoryListener.java:166)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.io.IOException: Stream closed
at java.base/sun.nio.cs.StreamEncoder.ensureOpen(StreamEncoder.java:51)
at java.base/sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.base/sun.nio.cs.StreamEncoder.write(StreamEncoder.java:142)
at java.base/java.io.OutputStreamWriter.write(OutputStreamWriter.java:223)
at java.base/java.io.Writer.write(Writer.java:249)
at org.metafacture.io.ObjectFileWriter.process(ObjectFileWriter.java:101)
... 4 more

  1. If path for the listen-directory points to a non existing directory [as it would be if the path points to a file instead of an directory] the listener starts. In my opinion it should throw an exception that the directory is missing.

  2. Additionally: I could improve the directory listener runner example after you finished working on this PR.

@TobiasNx TobiasNx assigned dr0i and unassigned TobiasNx Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add possibility to listen on a directory

4 participants