You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@camel.apache.org by Ron Cecchini <ro...@comcast.net> on 2020/09/01 05:37:47 UTC
Re: Asynchronously calling a route
Ok, I guess that was a little long. Let's try this:
Given this simple route:
from("seda:experiment")
.toD("http://localhost:8090/sleep?delay=${body}") // an endpoint that sleeps for 10*delay seconds
.process("MyProcessor");
How do I asynchronously call "seda:experiment" from another route?
I no longer even care to get a return (Exchange) from the route; "seda:experiment" can do all of the processing.
I just need to be able to call it and forget it.
I can't figure out what simple thing I'm missing, but none of the ProducerTemplate async*() calls are working - not even a simple asyncSendBody() - when I call "seda:experiment" in a loop, even when I'm not waiting for a return.
Instead of multiple sleep threads being started, each iteration waits for the previous sleep delay to finish.
Thanks for any help figuring out where my brain cramp is...
> On 08/28/2020 2:36 PM Ron Cecchini <ro...@comcast.net> wrote:
>
>
> 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.