This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new d9f888a814e4 CAMEL-25042: camel-core - the reload scan skips dot
directories, and scans every 2s again (#26925)
d9f888a814e4 is described below
commit d9f888a814e4cf8a018c324466d29f3587bd7cd1
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Sep 28 09:06:41 2026 +0200
CAMEL-25042: camel-core - the reload scan skips dot directories, and scans
every 2s again (#26925)
camel run keeps the properties of the run it is doing in
.camel-jbang/camel-jbang-run.properties and writes it more than once while
starting. The scan reported each write, the file ends in .properties, so the
strategy treated it as a properties change and reloaded the routes for it.
The
10 s poll of the watch service coalesced both writes into one batch, so it
happened once and was merely pointless; at 1 s they are two changes, and the
application reloaded twice a second apart. That is not harmless: an example
whose file consumer calls a rest route in the same application had the call
in
flight answered 404 by a rest route that the second reload was rebuilding.
A dot directory holds state, not sources, so the scan skips it, as it
already
skips the compile work directory (CAMEL-24862). That also stops it walking
.git
and .idea on every scan, which registering directories once never did. A
route
file inside a dot directory is no longer watched, which is intended.
The scan interval goes back to the previous default of 2000 ms, so
setPollTimeout's default is unchanged after all. A longer interval also
groups
more of one save together: two files written a second apart are one change
at
2000 and two at 1000, and one change is what a reload wants.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Bp3538HRBPMQkb5ta9xRaj
Signed-off-by: Claus Ibsen <[email protected]>
---
.../java/org/apache/camel/support/FileScanReloadTest.java | 15 +++++++++++++++
.../camel/support/FileWatcherResourceReloadStrategy.java | 12 ++++++++++--
.../modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 13 ++++++++-----
3 files changed, 33 insertions(+), 7 deletions(-)
diff --git
a/core/camel-core/src/test/java/org/apache/camel/support/FileScanReloadTest.java
b/core/camel-core/src/test/java/org/apache/camel/support/FileScanReloadTest.java
index 98f2f75d3b22..ee3c9e8505ce 100644
---
a/core/camel-core/src/test/java/org/apache/camel/support/FileScanReloadTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/support/FileScanReloadTest.java
@@ -133,6 +133,21 @@ public class FileScanReloadTest extends ContextTestSupport
{
assertThat(scanNames()).containsExactly("shop.yaml");
}
+ @Test
+ public void testADotDirectoryIsNotScanned() throws Exception {
+ // .camel-jbang holds the properties of the run camel-jbang is doing
and it rewrites them, which was reloading
+ // the routes; .git and .idea are not ours either (CAMEL-25042)
+ Path state = dir.resolve(".camel-jbang");
+ Files.createDirectories(state);
+ Files.writeString(dir.resolve("shop.yaml"), "one");
+ assertThat(scanNames()).containsExactly("shop.yaml");
+
+ Files.writeString(state.resolve("camel-jbang-run.properties"),
"camel.jbang.dev=true");
+ assertThat(scanNames()).isEmpty();
+ Files.writeString(state.resolve("camel-jbang-run.properties"),
"camel.jbang.dev=true\ncamel.jbang.x=1");
+ assertThat(scanNames()).isEmpty();
+ }
+
@Test
public void testASaveStillBeingWrittenIsLeftForTheNextScan() throws
Exception {
strategy.setStableTimeout(60_000);
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java
b/core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java
index 59945b15365c..50f23685a771 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/FileWatcherResourceReloadStrategy.java
@@ -69,7 +69,7 @@ public class FileWatcherResourceReloadStrategy extends
ResourceReloadStrategySup
String folder;
boolean isRecursive;
boolean scheduler = true;
- long pollTimeout = 1000;
+ long pollTimeout = 2000;
/**
* A file modified less than this ago is left for the next scan: a save
still being written would otherwise be
* reloaded half-finished. The file component leaves a file alone the same
way.
@@ -107,7 +107,8 @@ public class FileWatcherResourceReloadStrategy extends
ResourceReloadStrategySup
}
/**
- * Sets how often the folder is scanned for changed files, in millis. The
default value is 1000.
+ * Sets how often the folder is scanned for changed files, in millis. The
default value is 2000. A longer interval
+ * also groups more of one save together: two files written a second apart
are one change at 2000 and two at 1000.
*/
public void setPollTimeout(long pollTimeout) {
this.pollTimeout = pollTimeout;
@@ -219,6 +220,13 @@ public class FileWatcherResourceReloadStrategy extends
ResourceReloadStrategySup
// and would trigger a reload, which compiles again,
which writes again (CAMEL-24862)
return FileVisitResult.SKIP_SUBTREE;
}
+ if (!dir.equals(root) && dir.getFileName() != null
+ && dir.getFileName().toString().startsWith(".")) {
+ // a dot directory holds state, not sources:
.camel-jbang is where camel-jbang keeps the
+ // properties of the run it is doing, and rewriting
those was reloading the routes; .git and
+ // .idea are not ours either, and walking them every
scan costs for nothing (CAMEL-25042)
+ return FileVisitResult.SKIP_SUBTREE;
+ }
if (!isRecursive && !dir.equals(root)) {
return FileVisitResult.SKIP_SUBTREE;
}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 5f750d4fb38e..a5f89a84886d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -2963,8 +2963,11 @@ all the files of one save together, which is what a
reload needs: a route is bui
so a route and a property saved together must be reloaded together. It also
removes the macOS penalty, where Java has
no native file notification and the watch service fell back to a poll of about
ten seconds.
-`FileWatcherResourceReloadStrategy.setPollTimeout` is now how often the folder
is scanned, and its default changed
-from 2000 to 1000 milliseconds. On Linux and Windows a change is therefore
noticed within a second rather than
-immediately; on macOS within a second rather than up to ten. A new
`setStableTimeout` (default 200 milliseconds)
-leaves a file that was only just modified for the next scan, so a save still
being written is not reloaded
-half-finished.
+A dot directory under the watched folder is no longer scanned. `.camel-jbang`,
where `camel run` keeps the properties
+of the run it is doing, was reloading the routes whenever it was written, and
`.git` or `.idea` were walked on every
+scan for nothing. A route file inside a dot directory is therefore no longer
watched.
+
+`FileWatcherResourceReloadStrategy.setPollTimeout` is now how often the folder
is scanned. Its default is unchanged at
+2000 milliseconds, so on Linux and Windows a change is noticed within two
seconds rather than immediately, and on macOS
+within two seconds rather than up to ten. A new `setStableTimeout` (default
200 milliseconds) leaves a file that was
+only just modified for the next scan, so a save still being written is not
reloaded half-finished.