'Can't use onCompletion route scope with transacted routes

I didn't manage to customize transacted route with rollback/commit post-processing. Any help on how to write this kind of transacted route will be really appreciated. Based on some example code, I wrote something like this :

from(direct("global")
  .log("anything before that doesn't need transaction context")
  .to(direct("transacted")
  .log("anything after that doesn't need transaction context")
;

from(direct("transacted"))

  .onCompletion().onCompleteOnly()
    .validate().simple("${body.state} == 'MOVE_SUCCESS'")
    .log("success, with commit ")
  .end()

  .onCompletion().onFailureOnly()
    .validate().simple("${body.state} == 'WAITING_MOVE'")
    .bean(DbService.class, "documentInError(${body}, ${exception})")
    .bean(FileService.class, "moveFileToError")

    .log("error, with rollback")
  .end()

  .transacted()
    .bean(DbService.class, "updateDocument")
    .bean(FileService.class, "moveFileToTarget")      
;

but don't know why, I still have this kind of error :

Caused by: java.lang.IllegalArgumentException: The output must be added as top-level on the route. Try moving onCompletion[[]] to the top of route. at [email protected]/org.apache.camel.model.ProcessorDefinition.addOutput(ProcessorDefinition.java:209) ~[camel-core-model-3.15.0.jar:na] at [email protected]/org.apache.camel.model.ProcessorDefinition.onCompletion(ProcessorDefinition.java:3637) ~[camel-core-model-3.15.0.jar:na]

I'm permitted to declare those onCompletion only "outside" any route, but that doesn't correspond to what I want. Beacause then the onCompletion processing is hold in both global and transacted route, leading to other issues.

I already have onException application wise configured, with retry policy on FileService errors (handling redelivery of processor nodes). And would prefere to keep them configured application wise.

thanks,



Solution 1:[1]

We finally achieved kind of route scope of onCompletion and onException, by separating global route and transacted route in two distinct route builders.

But we decided to handle a transaction in java (spring) rather than in camel. Mainly because the transaction scope is difficult to figure out in camel. the transaction error handler, taking the lead once redelevery policy are exhausted, and somehow seems to happen within onException without clear demarcation :

for example :

onException(IOException)
  // the "following" (whatever holds behind the scene) happens inside transaction
  .maximumRedeliveries(3)
  .retryAttemptedLogLevel(WARN)
  .retriesExhaustedLogLevel(ERROR)
  .onExceptionOccurred(exceptionOccurredProcessor)
                
  // then on redelivery exhaustion the transaction is rolledback
  // the following happens after rollback
  .log(...)
  .to(...)

We had to make database operation support retries (due to some autonomous transactions), but this is simplier than structuring for camel transacted route.

Furthermore, it just happens that transacted route main purpose is the rollback of the message in the jms as well, but we don't want this because we handle errors with DLQs.

with_spring_transaction

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ugur Kurnaz