Serdar Gökay created CAMEL-25427:
------------------------------------
Summary: camel-support - on-demand route reload fails with
FileNotFoundException after a route file is removed from the source dir
Key: CAMEL-25427
URL: https://issues.apache.org/jira/browse/CAMEL-25427
Project: Camel
Issue Type: Bug
Components: camel-jbang, camel-core
Affects Versions: 4.22.1
Environment: Camel JBang 4.22.1, JBang 0.139.3, Java 25.0.4, macOS
Reporter: Serdar Gökay
On-demand route reload fails when one of several route files has been removed
from the source directory, for example after a route file was renamed. The
reload removes all routes and then fails with a FileNotFoundException for the
removed file. Afterwards no route runs, including the routes of files that did
not change, and every later on-demand reload fails the same way until the JVM
is restarted.
h3. Reproduce
Camel JBang 4.22.1 with two route files in a {{src}} directory:
{noformat}
# src/a.camel.yaml
- route:
id: a
from:
uri: timer:a?period=10000
steps:
- log: tick a
# src/b.camel.yaml
- route:
id: b
from:
uri: timer:b?period=10000
steps:
- log: tick b
{noformat}
{noformat}
camel run --source-dir=src --console --port=18761 --management-port=18762
# routes a and b start
rm src/b.camel.yaml
curl 'http://localhost:18762/q/dev/reload?reload=true'
curl -H 'Accept: application/json' http://localhost:18762/q/dev/route # no
routes left, a is gone too
curl 'http://localhost:18762/q/dev/reload?reload=true' # fails
again
{noformat}
Expected: route {{b}} is removed and route {{a}} is reloaded and keeps running.
Actual: both routes are gone, and each reload logs:
{noformat}
WARN RouteOnDemandReloadStrategy : Error reloading routes due to
java.io.FileNotFoundException: Resource not found: file:src/b.camel.yaml. This
exception is ignored.
org.apache.camel.RuntimeCamelException: java.io.FileNotFoundException: Resource
not found: file:src/b.camel.yaml
at
org.apache.camel.support.RouteWatcherReloadStrategy.onRouteReload(RouteWatcherReloadStrategy.java:388)
at
org.apache.camel.support.RouteOnDemandReloadStrategy.doOnReload(RouteOnDemandReloadStrategy.java:120)
at
org.apache.camel.support.RouteOnDemandReloadStrategy.onReload(RouteOnDemandReloadStrategy.java:75)
at
org.apache.camel.impl.console.ReloadDevConsole.lambda$doCallText$0(ReloadDevConsole.java:62)
Caused by: java.io.FileNotFoundException: Resource not found:
file:src/b.camel.yaml
at
org.apache.camel.dsl.yaml.YamlRoutesBuilderLoader.preParseRoute(YamlRoutesBuilderLoader.java:667)
at
org.apache.camel.impl.engine.DefaultRoutesLoader.findRoutesBuilders(DefaultRoutesLoader.java:165)
at
org.apache.camel.impl.engine.DefaultRoutesLoader.updateRoutes(DefaultRoutesLoader.java:295)
at
org.apache.camel.support.RouteWatcherReloadStrategy.onRouteReload(RouteWatcherReloadStrategy.java:319)
{noformat}
After the two reloads the reload dev console reports
{{"reloaded":0,"failed":2}}.
h3. Cause
{{RouteOnDemandReloadStrategy.findReloadedResources}} lists the files that
exist in the source directory, so a removed file is never passed to
{{onRouteReload}}. With {{removeAllRoutes}} (the default),
{{RouteWatcherReloadStrategy.onRouteReload}} then adds the source resource of
every current route that is not among the passed resources, without checking
that it still exists, and {{DefaultRoutesLoader.updateRoutes}} fails on the
removed file. The passed resources already get a {{Files.exists}} check; the
sources of the current routes do not. After the failure the attempted list is
kept in {{previousSources}} and added again on the next reload, so the failure
repeats.
The case where every route file is removed works, because {{removeEverything}}
clears the list before loading.
Code: [RouteWatcherReloadStrategy,
4.22.1|https://github.com/apache/camel/blob/camel-4.22.1/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java#L258-L295].
The same logic is on main: [RouteWatcherReloadStrategy,
main|https://github.com/apache/camel/blob/main/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java#L340-L380].
h3. Proposed change
When collecting the sources of the current routes and the remembered previous
sources, skip a source whose file no longer exists, with the same
{{Files.exists}} check the passed resources get. The routes of a removed file
are then removed like those of a changed file, and the other routes reload.
h3. Classification
Filed as a Bug because the reload fails on an ordinary edit (removing or
renaming a route file). We were not sure whether it should rather be an
Improvement, since on-demand reload only scans the files that exist. Please
reclassify it if Improvement fits better.
We came across this when a project was reloaded on demand after a Git pull that
had renamed one of its route files.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)