[ 
https://issues.apache.org/jira/browse/CAMEL-24630?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18113150#comment-18113150
 ] 

Claus Ibsen commented on CAMEL-24630:
-------------------------------------

Fixed via [PR #26173|https://github.com/apache/camel/pull/26173], merged to 
main as commit 857dc649dd0e4c4a32bd6b5caef889b5e5166ac2.

KameletComponent now only calls startRouteDefinitions() when the route does not 
yet exist in the route controller (getRouteStatus(id) == null), so a 
supervising controller no longer causes kamelet child routes to be materialized 
a second time on reload.

_Claude Code on behalf of davsclaus_

> camel-kamelet: supervised route reload creates duplicate internal routes and 
> causes context console NPE
> -------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24630
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24630
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-kamelet
>    Affects Versions: 4.18.1, 4.22.0
>         Environment: Apache Camel 4.18.1 and 4.22.0; Java 21.0.10 (Eclipse 
> Temurin), Linux aarch64. DefaultSupervisingRouteController enabled. 
> Reproduced with standalone native Camel APIs and separately with Camel JBang 
> management reload/status endpoints. No JDK 25 or virtual-thread configuration 
> is required.
>            Reporter: Serdar Gökay
>            Assignee: Omar Atie
>            Priority: Minor
>             Fix For: 4.23.0
>
>
> h3. What happens
> Reloading a Kamelet route with DefaultSupervisingRouteController enabled 
> creates duplicate internal route entries. A subsequent reload leaves an entry 
> for which getRouteStatus(routeId) returns null. 
> ManagedCamelContext.getStartedRoutes() then throws NullPointerException; the 
> Camel JBang context dev console returns HTTP 500.
> Reproduced with unmodified Apache Camel 4.18.1 and 4.22.0 on Java 21. The 
> standalone reproducer below uses only native Camel dependencies and APIs; no 
> application framework, Kubernetes or external service is required.
> h3. Expected behavior
> The example contains one parent route and one Kamelet-created route. After 
> each reload, the context should still contain two unique routes and 
> started-route introspection should succeed.
> h3. Observed behavior
> * Initial startup: 2 routes, both Started.
> * After the first reload: 3 entries; the same Kamelet route ID appears twice.
> * After the second reload: 4 entries; an old Kamelet route ID has null status 
> and getStartedRoutes() throws NPE.
> * In the JBang runtime, timer messages continue while /q/dev/context 
> repeatedly returns HTTP 500. This was not a process crash.
> * A control run without the supervising controller did not reproduce the 
> duplicate entries.
> h3. Reproduction
> Save the two files below as pom.xml and SupervisedKameletReload.java in an 
> empty directory. Run from that directory with Java 21 and Maven:
> {code:bash}
> mvn -q -Dcamel.version=4.22.0 
> org.apache.maven.plugins:maven-dependency-plugin:3.8.1:build-classpath 
> -Dmdep.outputFile=classpath.txt
> java -Dorg.slf4j.simpleLogger.defaultLogLevel=warn -cp "$(cat classpath.txt)" 
> SupervisedKameletReload.java
> {code}
> Repeat the Maven command with -Dcamel.version=4.18.1 and run the Java command 
> again to reproduce on 4.18.1.
> The reproducer creates a local route template consumed through kamelet:, 
> enables DefaultSupervisingRouteController with an initial delay of 1000 ms, 
> then repeats the native stop/remove, route-template cleanup, 
> endpoint-registry cleanup and route loading sequence. It prints route IDs and 
> statuses before querying getStartedRoutes(). The same route-count progression 
> and NPE were observed on both versions.
> The same symptom was also reproduced using native Camel JBang management 
> requests: /q/dev/reload?reload=true&wait=true followed by /q/dev/context with 
> Accept: application/json.
> h3. Example output (4.22.0)
> {code}
> After 0 reload(s), routes=2
> probe-parent status=Started
> probe-source-1 status=Started
> Started routes=2
> After 1 reload(s), routes=3
> probe-source-3 status=Started
> probe-source-3 status=Started
> probe-parent status=Started
> Started routes=3
> After 2 reload(s), routes=4
> probe-source-3 status=null
> probe-source-5 status=Started
> probe-source-5 status=Started
> probe-parent status=Started
> Exception in thread "main" java.lang.NullPointerException: Cannot invoke 
> "org.apache.camel.ServiceStatus.isStarted()" because the return value of 
> "org.apache.camel.spi.RouteController.getRouteStatus(String)" is null
>     at 
> org.apache.camel.management.mbean.ManagedCamelContext.getStartedRoutes(ManagedCamelContext.java:314)
>     at SupervisedKameletReload.main(SupervisedKameletReload.java:32)
> {code}
> In 4.18.1, the corresponding ManagedCamelContext frame is line 312.
> h3. pom.xml
> {code:xml}
> <?xml version="1.0" encoding="UTF-8"?>
> <project xmlns="http://maven.apache.org/POM/4.0.0"; 
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
> https://maven.apache.org/xsd/maven-4.0.0.xsd";>
>     <modelVersion>4.0.0</modelVersion>
>     <groupId>example</groupId>
>     <artifactId>camel-supervised-kamelet-reproducer</artifactId>
>     <version>1</version>
>     <properties><camel.version>4.18.1</camel.version></properties>
>     <dependencies>
>         
> <dependency><groupId>org.apache.camel</groupId><artifactId>camel-kamelet</artifactId><version>${camel.version}</version></dependency>
>         
> <dependency><groupId>org.apache.camel</groupId><artifactId>camel-management</artifactId><version>${camel.version}</version></dependency>
>         
> <dependency><groupId>org.apache.camel</groupId><artifactId>camel-timer</artifactId><version>${camel.version}</version></dependency>
>         
> <dependency><groupId>org.apache.camel</groupId><artifactId>camel-log</artifactId><version>${camel.version}</version></dependency>
>         
> <dependency><groupId>org.apache.camel</groupId><artifactId>camel-core-languages</artifactId><version>${camel.version}</version></dependency>
>         
> <dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>2.0.17</version></dependency>
>     </dependencies>
> </project>
> {code}
> h3. SupervisedKameletReload.java
> {code:java}
> import org.apache.camel.builder.RouteBuilder;
> import org.apache.camel.impl.DefaultCamelContext;
> import org.apache.camel.impl.engine.DefaultSupervisingRouteController;
> import org.apache.camel.management.mbean.ManagedCamelContext;
> public class SupervisedKameletReload {
>     static RouteBuilder routes() {
>         return new RouteBuilder() {
>             public void configure() {
>                 routeTemplate("probe-source")
>                     .from("timer:probe?repeatCount=1&delay=10")
>                     .setBody(constant("hello")).to("kamelet:sink");
>                 from("kamelet:probe-source").routeId("probe-parent")
>                     .process(exchange -> {});
>             }
>         };
>     }
>     public static void main(String[] args) throws Exception {
>         try (var context = new DefaultCamelContext()) {
>             var controller = new DefaultSupervisingRouteController();
>             controller.setInitialDelay(1000);
>             context.setRouteController(controller);
>             context.addRoutes(routes());
>             context.start();
>             for (int iteration = 0; iteration <= 2; iteration++) {
>                 Thread.sleep(1500);
>                 System.out.println("After " + iteration + " reload(s), 
> routes=" + context.getRoutesSize());
>                 for (var route : context.getRoutes()) {
>                     System.out.println(route.getId() + " status=" + 
> controller.getRouteStatus(route.getId()));
>                 }
>                 System.out.println("Started routes=" + new 
> ManagedCamelContext(context).getStartedRoutes());
>                 if (iteration == 2) break;
>                 controller.removeAllRoutes();
>                 context.removeRouteTemplates("*");
>                 context.getEndpointRegistry().clear();
>                 context.addRoutes(routes());
>             }
>         }
>     }
> }
> {code}



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to