2
votes

I have couple of routes (route 1 and route 2) in my Spring Boot application. I have been researching how to gracefully shutdown the application after processing both the routes. I have referred the documentation (https://camel.apache.org/manual/latest/graceful-shutdown.html) but couldn't successfully achieve what I needed. Maybe my understanding is wrong.

Below are my two routes

Route 1

 from("timer://runOnce?repeatCount=1")
     .to("{{sql.selectAll}}")
......... SOME PROCESSING
     .to("direct:checkStatus")

Route 2

from("direct:checkStatus")
     .delay(5000)
     .loopDoWhile(CONDITION)
          .process(DO_SOMETHING)
     .end()
     .to("jpa:com.pqr.MyClass)
     .stop();

I have tried all these options

1. Automatic shutdown after 60 seconds

camel.springboot.duration-max-seconds = 60

It does GRACEFULLY shutdown the 2 routes but then WARNs about FORCEFUL shutdown ExecutorsService and also it doesn't stop the main thread to stop the application.

2020-03-01 18:28:25.507  WARN 30279 --- [otTerminateTask] o.a.c.i.e.BaseExecutorServiceManager     : Forcing shutdown of ExecutorService: org.apache.camel.util.concurrent.SizedScheduledExecutorService@17fbfb02[CamelSpringBootTerminateTask] due first await termination elapsed.
2020-03-01 18:28:25.507  WARN 30279 --- [otTerminateTask] o.a.c.i.e.BaseExecutorServiceManager     : Forcing shutdown of ExecutorService: org.apache.camel.util.concurrent.SizedScheduledExecutorService@17fbfb02[CamelSpringBootTerminateTask] due interrupted.
2020-03-01 18:28:25.508  INFO 30279 --- [otTerminateTask] o.a.c.i.e.BaseExecutorServiceManager     : Shutdown of ExecutorService: org.apache.camel.util.concurrent.SizedScheduledExecutorService@17fbfb02[CamelSpringBootTerminateTask] is shutdown: true and terminated: false took: 10.004 seconds.
2020-03-01 18:28:25.508  WARN 30279 --- [otTerminateTask] o.a.c.i.e.BaseExecutorServiceManager     : Forced shutdown of 1 ExecutorService's which has not been shutdown properly (acting as fail-safe)
2020-03-01 18:28:25.508  WARN 30279 --- [otTerminateTask] o.a.c.i.e.BaseExecutorServiceManager     :   forced -> org.apache.camel.util.concurrent.SizedScheduledExecutorService@17fbfb02[CamelSpringBootTerminateTask]

2. Initiate shutdown from the Route2

    from("direct:checkStatus")
            .delay(5000)
            .loopDoWhile(CONDITION)
                 .process(DO_SOMETHING)
            .end()
            .to("jpa:com.pqr.MyClass)
            .process(exchange -> {
                exchange.getContext().getRouteController().stopRoute("route1");
                exchange.getContext().getRouteController().stopRoute("route2");
                System.out.println("Route1 -->"+exchange.getContext().getRouteController().getRouteStatus("route1"));
                System.out.println("Route2 -->"+exchange.getContext().getRouteController().getRouteStatus("route2"));
                exchange.getContext().shutdown();
            });

"route1" is gracefully stopped but "route2" fails to be gracefully stopped with below message and waits for default timeout (300s).

2020-03-01 18:35:29.113  INFO 30504 --- [read #4 - Delay] o.a.c.i.engine.DefaultShutdownStrategy   : Starting to graceful shutdown 1 routes (timeout 300 seconds)
2020-03-01 18:35:29.116  INFO 30504 --- [ - ShutdownTask] o.a.c.i.engine.DefaultShutdownStrategy   : Route: route1 shutdown complete, was consuming from: timer://runOnce?repeatCount=1
2020-03-01 18:35:29.116  INFO 30504 --- [read #4 - Delay] o.a.c.i.engine.DefaultShutdownStrategy   : Graceful shutdown of 1 routes completed in 0 seconds
2020-03-01 18:35:29.117  INFO 30504 --- [read #4 - Delay] o.a.c.s.boot.SpringBootCamelContext      : Route: route1 is stopped, was consuming from: timer://runOnce?repeatCount=1
2020-03-01 18:35:29.117  INFO 30504 --- [read #4 - Delay] o.a.c.i.engine.DefaultShutdownStrategy   : Starting to graceful shutdown 1 routes (timeout 300 seconds)
2020-03-01 18:35:29.118  INFO 30504 --- [ - ShutdownTask] o.a.c.i.engine.DefaultShutdownStrategy   : Waiting as there are still 1 inflight and pending exchanges to complete, timeout in 300 seconds. Inflights per route: [route2 = 1]

It looks like there is a pending exchange message to be consumed. Do I need to manually clear/consume the exchange message in order to clear and facilitate a graceful shutdown?

Either option doesn't stop the main application. Do I have to write a custom Shutdown strategy instead of DefaultShutdownStrategy to achieve this? Can someone kindly point to an example to shut down the Spring Boot application after completion of the routes? Thanks in advance!!!

1
I think you can get SpringApplicationContext and call exit method on application on passing context as show here: baeldung.com/spring-boot-shutdown#exit, do this once process is completeddkb

1 Answers

2
votes

Did you try to use exchange.getContext().stop() to stop main application?

To force stop route without waiting for default timeout you can use exchange.getContext().stopRoute(routeId, 1L, TimeUnit.SECONDS); or set your timeout in seconds context.getShutdownStrategy().setTimeout(30);