Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache Camel: do not trigger route if previous route run is not complete

I have such a situation:

  • Apache Camel route is triggered by timer
  • route executes massive lengthy task
  • and it is possible for timer to trigger route again while previous run is still underway.

I would like my route NOT to be re-triggered while massive task is underway. That is, timer may issue event but it should somehow not lead to trigger route. When massive task is finished, it should be possible for timer to start route again.

What would be the best way to achieve this behaviour?

like image 686
onkami Avatar asked Aug 25 '16 10:08

onkami


3 Answers

This is a dsl version that has worked for me:

private static final AtomicBoolean readyToProcess = new AtomicBoolean(true);

public static boolean readyToProcess() {
    boolean readyToProcess = AlarmRouteBuilder.readyToProcess.get();
    if (readyToProcess) {
        AlarmRouteBuilder.readyToProcess.set(false);
    }
    return readyToProcess;
}

@Override
public void configure() throws Exception {

    from("timer://alarm-poll?period=5s").routeId("alarm-poll")
            .log(LoggingLevel.INFO, "Start Timer")
            .filter(method(AlarmRouteBuilder.class, "readyToProcess"))
            .to("direct:alarm-dostuff")
            .end()
            .log(LoggingLevel.INFO, "End Timer")
    ;

    from("direct:alarm-dostuff").routeId("alarm-dostuff")
//            .process(exchange -> readyToProcess.set(false))
            .process(exchange -> doStuff())
            .process(exchange -> readyToProcess.set(true))
    ;
like image 132
Thomas Newman Avatar answered Nov 20 '22 08:11

Thomas Newman


Well, my first reflex would be to use the timer's period option without the fixedRate option (i.e. set the fixedRate option to false):

So, declaring:

from("timer:myTask?[other_options]&fixedRate=false")
    .to("direct:lengthyProcessingRoute")

should wait for the task to complete before triggering the timer again.

For instance, declaring a route like (fixedRate is false by default):

from("timer:sender?delay=5s&period=3s")
        .log("Ping!")
        .delay(5000)
        .log("Ping2!");

will always give the output of:

2016-08-26 12:36:48.130  INFO 5775 --- [ timer://sender] route1 : Ping!
2016-08-26 12:36:53.133  INFO 5775 --- [ timer://sender] route1 : Ping2!
2016-08-26 12:36:53.135  INFO 5775 --- [ timer://sender] route1 : Ping!
2016-08-26 12:36:58.138  INFO 5775 --- [ timer://sender] route1 : Ping2!

However, this will only work if your lengthy processing route is synchronous in nature. If it's not, then you would have to do something similar to what JimNicholson is suggesting in his answer.

like image 27
Miloš Milivojević Avatar answered Nov 20 '22 08:11

Miloš Milivojević


I would create a bean to hold the running/finished state of the route with methods to set the state and a method to test the state. Then I would do something like this:

<route>
  <from uri="timer:...">
  <filter>
    <method ref="routeStateBean" method="isStopped">
    <to uri="bean:routeStateBean?method=routeStarted"/>
    ....
    <to uri="bean:routeStateBean?method=routeStopped"/>
  </filter>
</route>
like image 1
JimNicholson Avatar answered Nov 20 '22 07:11

JimNicholson