Hi, guys. I've been following the "async" docs and examples and the few code
snippets I could find online, but I'm still having trouble doing something that
I would think is very common.
My use case is basically this:
1. I have a small route (call it "experiment") that hits an HTTP endpoint and
returns the integer value returned by that endpoint.
2. I need to asynchronously call this "experiment" route from within a loop, or
from a barrage of JMS messages, etc.
----------
To test this, I created a small separate service sitting on port 8090 with
endpoint "/experiment?i=<value>".
The endpoint just calculates a delay, sleeps, and returns the delay:
@GetMapping(value = "/experiment")
public Integer sedaExperiment (@RequestParam(name = "i", required = true)
Integer ival) throws InterruptedException
{
log.info(String.format("sedaExperiment: ival: %d", ival));
delay = 10 + ival*10;
log.info(String.format("sedaExperiment: %d - sleeping %d seconds...",
ival, delay));
Thread.sleep(delay * 1000L);
log.info(String.format("sedaExperiment: %d - returning: %d", ival,
delay));
return delay;
}
----------
In my calling app, my "experiment" route is simple enough:
from("seda:experiment")
.routeId("seda-experiment")
.setHeader("val", simple("${body}"))
.log(LoggingLevel.INFO, "Experiment: ${header.val}")
.toD("http://localhost:8090/experiment?i=${header.val}")
.log(LoggingLevel.INFO, "Experiment: ${header.val} - results:
${body}");
And here's where I call it in a loop:
from("timer:experiment?repeatCount=1")
.routeId("timer-experiment")
.process(new Processor() {
public void process(Exchange e) throws Exception {
ProducerTemplate prod =
e.getContext().createProducerTemplate();
MyCallback callback = new MyCallback();
for ( int i = 1; i <= 3; i++ ) {
log.info(String.format("*** i = %d", i));
// prod.asyncSendBody("seda:experiment", i, callback);
// prod.asyncRequestBody("seda:experiment", i, callback);
// prod.asyncCallbackSendBody("seda:experiment", i,
callback);
prod.asyncCallbackRequestBody("seda:experiment", i,
callback);
//
prod.asyncCallbackSendBody("http://localhost:8090/experiment?i="+i, null,
callback);
}
}
});
where 'callback' is:
private static class MyCallback extends SynchronizationAdapter {
@Override
public void onComplete(Exchange exchange) {
Integer result = exchange.getIn().getBody(Integer.class);
log.info(String.format("ASYNC: Experiment: %d - results: %d", 99,
result));
}
}
-------------------------
What ends up happening is that the "seda:experiment" route is called
sequentially, with each call waiting for the service's endpoint's delay to
finish. Obviously not async...
Besides asyncCallbackRequestBody(), you can see I experimented with other async
calls. Nothing worked as desired.
The closest thing that worked was not calling my "seda:experiment" route but
calling the endpoint directly:
asyncCallbackSendBody("http://localhost:8090/experiment?i="+i, null, callback);
This *did* kick off 3 simultaneous threads on the service side. However, the
results don't seem to be in the callback ('result' is null, not 20, 30, 40).
But even if I could get the result in the callback, I'd *really* rather be able
to call my route because the (real) route contains extra processing that I
don't want to try replicating in the callback.
-------------------------
So what am I doing wrong? I know this must be something people do ALL THE
TIME...
As for the callback stuff, if I could call "seda:experiment" asynchronously, I
wouldn't even need any of the "Callback" versions of any of the async*() calls.
The route does everything I need. I just can't call it properly...
As always, thank you for any help.