How can I send a message to an endpoint without waiting for that endpoint's route to be process (that is, my route should just dispatch the message and finish)?
Using wireTap or multicast is what you're after. A direct: endpoint will modify the Exchange for the next step no matter what ExchangePattern is specified. You can see by using this failing test:
public class StackOverflowTest extends CamelTestSupport {
private static final String DIRECT_INPUT = "direct:input";
private static final String DIRECT_NO_RETURN = "direct:no.return";
private static final String MOCK_OUTPUT = "mock:output";
private static final String FIRST_STRING = "FIRST";
private static final String SECOND_STRING = "SECOND";
#NotNull
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from(DIRECT_INPUT)
.to(ExchangePattern.InOnly, DIRECT_NO_RETURN)
.to(MOCK_OUTPUT)
.end();
from(DIRECT_NO_RETURN)
.bean(new CreateNewString())
.end();
}
};
}
#Test
public void testShouldNotModifyMessage() throws JsonProcessingException, InterruptedException {
final MockEndpoint myMockEndpoint = getMockEndpoint(MOCK_OUTPUT);
myMockEndpoint.expectedBodiesReceived(FIRST_STRING);
template.sendBody(DIRECT_INPUT, FIRST_STRING);
assertMockEndpointsSatisfied();
}
public static class CreateNewString {
#NotNull
public String handle(#NotNull Object anObject) {
return SECOND_STRING;
}
}
}
Now if you change the above to a wireTap:
from(DIRECT_INPUT)
.wireTap(DIRECT_NO_RETURN)
.to(MOCK_OUTPUT)
.end();
and you'll see it works as expected. You can also use multicast:
from(DIRECT_INPUT)
.multicast()
.to(DIRECT_NO_RETURN)
.to(MOCK_OUTPUT)
.end();
wireTap(endpoint) is the answer.
you can use a ProducerTemplate's asyncSend() method to send an InOnly message to an endpoint...
template.asyncSend("direct:myInOnlyEndpoint","myMessage");
see http://camel.apache.org/async.html for some more details
That might depend on what endpoints etc you are using, but one common method is to put a seda endpoint in between is one option.
from("foo:bar")
.bean(processingBean)
.to("seda:asyncProcess") // Async send
.bean(moreProcessingBean)
from("seda:asyncProcess")
.to("final:endpoint"); // could be some syncrhonous endpoint that takes time to send to. http://server/heavyProcessingService or what not.
The seda endpoint behaves like a queue, first in - first out. If you dispatch several events to a seda endpoint faster than the route can finish processing them, they will stack up and wait for processing, which is a nice behaviour.
You can use inOnly in your route to only send your message to an endpoint without waiting for a response. For more details see the request reply documentation or the event message documentation
from("direct:testInOnly").inOnly("mock:result");
https://people.apache.org/~dkulp/camel/async.html
Both for InOnly and InOut you can send sync or async. Seems strange that you can send InOnly but async, but at last here it explains that it waits for Camel processing and then fire and forget.
The Async Client API
Camel provides the Async Client API in the ProducerTemplate where we have added about 10 new methods to Camel 2.0. We have listed the most important in the table below:
Method
Returns
Description
setExecutorService
void
Is used to set the Java ExecutorService. Camel will by default provide a ScheduledExecutorService with 5 thread in the pool.
asyncSend
Future
Is used to send an async exchange to a Camel Endpoint. Camel will imeddiately return control to the caller thread after the task has been submitted to the executor service. This allows you to do other work while Camel processes the exchange in the other async thread.
asyncSendBody
Future
As above but for sending body only. This is a request only messaging style so no reply is expected. Uses the InOnly exchange pattern.
asyncRequestBody
Future
As above but for sending body only. This is a Request Reply messaging style so a reply is expected. Uses the InOut exchange pattern.
extractFutureBody
T
Is used to get the result from the asynchronous thread using the Java Concurrency Future handle.
The Async Client API with callbacks
In addition to the Client API from above Camel provides a variation that uses callbacks when the message Exchange is done.
Method
Returns
Description
asyncCallback
Future
In addition a callback is passed in as a parameter using the org.apache.camel.spi.Synchronization Callback. The callback is invoked when the message exchange is done.
asyncCallbackSendBody
Future
As above but for sending body only. This is a request only messaging style so no reply is expected. Uses the InOnly exchange pattern.
asyncCallbackRequestBody
Future
As above but for sending body only. This is a Request Reply messaging style so a reply is expected. Uses the InOut exchange pattern.
These methods also returns the Future handle in case you need them. The difference is that they invokes the callback as well when the Exchange is done being routed.
The Future API
The java.util.concurrent.Future API have among others the following methods:
Method
Returns
Description
isDone
boolean
Returns a boolean whether the task is done or not. Will even return true if the tasks failed due to an exception thrown.
get()
Object
Gets the response of the task. In case of an exception was thrown the java.util.concurrent.ExecutionException is thrown with the caused exception.
Related
I am currently on a Project that builds Microservices, and are trying to move from the more traditional Spring Boot RestClient to Reactive Stack using Netty and WebClient as the HTTP Client in order to connect to backend systems.
This is going well for backends with REST APIs, however I'm still having some difficulties implementing WebClient to services that connect to SOAP backends and Oracle databases, which still uses traditional JDBC.
I managed to find some workaround online regarding JDBC calls that make use of parallel schedulers to publish the result of the blocking JDBC call:
//the method that is called by #Service
#Override
public Mono<TransactionManagerModel> checkTransaction(String transactionId, String channel, String msisdn) {
return asyncCallable(() -> checkTransactionDB(transactionId, channel, msisdn))
.onErrorResume(error -> Mono.error(error));
}
...
//the actual JDBC call
private TransactionManagerModel checkTransactionDB(String transactionId, String channel, String msisdn) {
...
List<TransactionManagerModel> result =
jdbcTemplate.query(CHECK_TRANSACTION, paramMap, new BeanPropertyRowMapper<>(TransactionManagerModel.class));
...
}
//Generic async callable
private <T> Mono<T> asyncCallable(Callable<T> callable) {
return Mono.fromCallable(callable).subscribeOn(Schedulers.parallel()).publishOn(transactionManagerJdbcScheduler);
}
and I think this works quite well.
While for SOAP calls, what I did was encapsulating the SOAP call in a Mono while the SOAP call itself is using a CloseableHttpClient which is obviously a blocking HTTP Client.
//The method that is being 'reactive'
public Mono<OfferRs> addOffer(String transactionId, String channel, String serviceId, OfferRq request) {
...
OfferRs result = adapter.addOffer(transactionId, channel, generateRequest(request));
...
}
//The SOAP adapter that uses blocking HTTP Client
public OfferRs addOffer(String transactionId, String channel, JAXBElement<OfferRq> request) {
...
response = (OfferRs) getWebServiceTemplate().marshalSendAndReceive(url, request, webServiceMessage -> {
try {
SoapHeader soapHeader = ((SoapMessage) webServiceMessage).getSoapHeader();
ObjectFactory headerFactory = new ObjectFactory();
AuthenticationHeader authHeader = headerFactory.createAuthenticationHeader();
authHeader.setUserName(username);
authHeader.setPassWord(password);
JAXBContext headerContext = JAXBContext.newInstance(AuthenticationHeader.class);
Marshaller marshaller = headerContext.createMarshaller();
marshaller.marshal(authHeader, soapHeader.getResult());
} catch (Exception ex) {
log.error("Failed to marshall SOAP Header!", ex);
}
});
return response;
...
}
My question is: Does this implementation for SOAP calls "reactive" enough that I won't have to worry about some calls being blocked in some part of the microservice? I have already implemented reactive stack - calling a block() explicitly will throw an exception as it's not permitted if using Netty.
Or should I adapt the use of parallel Schedulers in SOAP calls as well?
After some discussions i'll write an answer.
Reactor documentation states that you should place blocking calls on their own schedulers. Thats basically to keep the non-blocking part of reactor going, and if something comes in that blocks, then reactor will fallback to traditional servlet behaviour which means assigning one thread to each request.
Reactor has very good documentation about schedulers their types etc.
But short:
onSubscribe
When someone subscribes, reactor will go into something called the assembly phase which means it will basically from the subscribe point start calling the operators backwards upstream until it finds a producer of data (for example a database, or another service etc). If it finds a onSubscribe-operator somewhere during this phase it will place this entire chain on its own defined Scheduler. So one good thing to know is that placement of the onSubscribe does not really matter, as long as it is found during the assembly phase the entire chain will be affected.
Example usage could be:
We have blocking calls to a database, slow calls using a blocking rest client, reading a file from the system in a blocking manor etc.
onPublish
if you have onPublish somewhere in the chain during the assembly phase the chain will know that where it is placed the chain will switch from the default scheduler to the designated scheduler at that specific point. So onPublish placement DOES matter. As it will switch at where it is placed. This operator is more to control that you want to place something on a specific scheduler at specific point in the code.
Examples usage could be:
You are doing some heavy blocking cpu calculations at a specific point, you could switch to a Scheduler.parallell() that will guarantee that all calculations will be placed on separate cores do do heavy cpu work, and when you are done you could switch back to the default scheduler.
Above example
Your soap calls should be placed on its own Scheduler if they are blocking and i think onSubscribe will be enough with a usage of a Schedulers.elasticBound() will be fine to get traditional servlet behaviour. If you feel like you are scared of having every blocking call on the same Scheduler, you could pass in the Scheduler in the asyncCallable function and split up calls to use different Schedulers.
I need to show off an example of server sent events. I learned about it in a spring talk. People used Webflux there to show the reactive principles. I understood the part on how this will free thread resources because the request thread won't be blocked until the job is done and the server returns the response.
I have an example here but actually I don't really know how I can make this thread resource example be clear enough.
I do not want to use the WebFlux framework here. Just need to know what to put into a separate thread here - if necessary at all?!
As you can see I have a GetMapping to subscribe to the event stream. And then I have a GetMapping to launch or fire an event. This example is fast for sure but should be considered as heavy database call.
So I actually need to have the whole logic be separated in another thread right? So the request thread is free as soon as possible?
#RestController
public class EventStreamRequestHandler {
#Autowired
ObjectMapper objectMapper;
SseEmitter sseEmitter = new SseEmitter(1000000L);
#GetMapping("/get/event/stream")
public SseEmitter getStream() {
return this.sseEmitter;
}
#GetMapping("/launch/event")
public void fireEvent() throws IOException {
Person peter = new Person("Peter", "25");
String valueAsString = objectMapper.writeValueAsString(peter);
SseEmitter.SseEventBuilder sseEventBuilder = SseEmitter.event()
.id("foo")
.name("awesome-event")
.data(valueAsString);
sseEmitter.send(sseEventBuilder);
}
}
Yes, Server sent events are supposed to send messages to the client asynchronously without client keep on polling for message.
The sending of messages from client to server needs to be done asynchronously. With the way you have done it. When a GET request is sent to /get/event/stream an SseEmitter will be created but messages will only be sent when a GET request is sent to /launch/event. And the GET request thread for /launch/event will be used to send the message.
Sometime back I wrote post to send SSE messages using a different thread. I hope this helps.
But I don't recommend storing the SseEmitter in an instance variable as it will overridden by multiple requests. You must at least make it ThreadLocal
I have a hub and spoke architecture similar to this:
where a GET request comes into the hub and it routes it to one of the spokes for processing. On the hub I also put the request in a map with a UUID so that I can return the proper response when I get the data back from processing. The spokes are identical and are used to balance the load. I then need to pass the information back to the hub from the spoke and return the proper reponse.
I would like to do the messaging using JMS.
What is the best combination of integration patterns to accomplish this?
You already have Request/Reply within Vert.x, so you can achieve this behavior with about 20 lines of code:
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
Router router = Router.router(vertx);
router.get("/").handler((request) -> {
// When hub receives request, it dispatches it to one of the Spokes
String requestUUID = UUID.randomUUID().toString();
vertx.eventBus().send("processMessage", requestUUID, (spokeResponse) -> {
if (spokeResponse.succeeded()) {
request.response().end("Request " + requestUUID + ":" + spokeResponse.result().body().toString());
}
// Handle errors
});
});
// We create two Spokes
vertx.deployVerticle(new SpokeVerticle());
vertx.deployVerticle(new SpokeVerticle());
// This is your Hub
vertx.createHttpServer().requestHandler(router::accept).listen(8888);
}
And here's what Spoke looks like:
/**
* Static only for the sake of example
*/
static class SpokeVerticle extends AbstractVerticle {
private String id;
#Override
public void start() {
this.id = UUID.randomUUID().toString();
vertx.eventBus().consumer("processMessage", (request) -> {
// Do something smart
// Reply
request.reply("I'm Spoke " + id + " and my reply is 42");
});
}
}
Try accessing it in your browser on http://localhost:8888/
You should see that request ID is generated every time, while only one of two Spokes answers your request.
Well if I understand your design correctly this seems to request/reply scenario since the spoke is actually returning some response. If it didn't it would be publish/subscribe.
You can use ActiveMQ for jms and request/reply. See here:
http://activemq.apache.org/how-should-i-implement-request-response-with-jms.html
As for the details it all depends on your requirements, will the response be sent fairly immediately or is it a long running process?
If it is a long running process you can avoid request/reply and use a fire and forget scenario.
Basically, the hub fires a message on a queue which is being listened by one of the spoke components. Once the backend processing is done it returns the response to a queue monitored by the hub. You can correlate the request/response via some correlationId. During the request part, you can save the correlationId in a cache to match against the response. In a request/reply scenario this is done for you by the infrastructure but don't use for long running process.
To summarise:
Use ActiveMQ for your message processing with JMS.
Use Camel for the REST bits.
Use request/reply if you are sure you expect a response fairly rapidly.
Use fire and forget if you expect the response to take a long time but have to match the message correlationIds.
If you wish to use Camel with JMS, then you should use Request-Reply EIP, and as far as examples go, you have a pretty good one provided via Camel's official examples - it may be a bit old but it's still very much valid.
While you can just ignore the example's Camel configuration through Spring, its route definitions provide sufficient information:
public class SpokeRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("jms:queue:spoke")
.process(e -> {
Object result = ...; // do some processing
e.getIn().setBody(result); // publish the result
// Camel will automatically reply if it finds a ReplyTo and CorrelationId headers
});
}
}
Then all HUB needs to do is invoke:
ProducerTemplate camelTemplate = camelContext.createProducerTemplate();
Object response = camelTemplate.sendBody("jms:queue:spoke", ExchangePattern.InOut, input);
I am developing a jax-ws webservice that pushes messages asynchronously to the subscribed consumers using one-way operation.
Unfortunatelly with each notification, server awaits a HTTP202 response confirmation which blocks the thread for a fraction of a second. This is affecting the performance of the system and I am looking for a way around this.
Is there any way to execute a web-service one-way call and ignore the HTTP response status?
Ok, so after spending a lot of time on this I have found two solutions:
1) Using Apache HTTPComponents, which provide AsyncHTTPClient with nice API allowing us to build a HTTP response from the scratch.
2) More web-service oriented solution based on Apache CXF platform (which includes the HTTPClient implementation) - first we need to set the global Bus property:
Bus bus = BusFactory.getDefaultBus();
bus.setProperty(AsyncHTTPConduit.USE_ASYNC, Boolean.TRUE);
Then, we use custom interceptor to set the message exchange property to asynchronous:
final class SkipWaitInterceptor extends AbstractSoapInterceptor {
SkipWaitInterceptor() {
super(Phase.SETUP);
}
#Override
public void handleMessage(final SoapMessage message) throws Fault {
message.getExchange().setSynchronous(false);
}
}
Finally, we register the interceptor on our asynchronous Endpoint
org.apache.cxf.endpoint.Client client =
org.apache.cxf.frontend.ClientProxy.getClient(this.notificationConsumer);
org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
cxfEndpoint.getOutInterceptors().add(new SkipWaitInterceptor());
That's all, one-way operation responses no longer block the communication.
I have just started experimenting with Spring and rabbitMQ.
I would like to create a microsevice infrastructure with rabbit and spring,
I have been following Spring boot tutorial
But it is very simplistic. As well I am looking at the documentation (springs, Rabbit) for how to create an RPC, i understand the Rabbits approach, but i would like to leverage Spring template to save me the boilerplate.
I just cant seem to understand where to register the reciveAndReplay callback at.
I tried doing this:
sending
System.out.println("Sending message...");
Object convertSendAndReceive = rabbitTemplate.convertSendAndReceive("spring-boot", "send and recive: sent");
System.out.println("GOT " + convertSendAndReceive); //is null
receiving
#Component
public class Receiver {
#Autowired
RabbitTemplate rabbitTemplate;
public void receiveMessage(String message) {
this.rabbitTemplate.receiveAndReply("spring-boot", (Message)->{
return "return this statement";
});
}
}
But its not a big surprise this doesn't work the message is received but nothing comes back. I assume that this needs to be registered somewhere in the factory/template at the bean creation level but i don't seem to understand where and sadly the documentation is unclear.
First, please use the Spring AMQP Documentation.
You would generally use a SimpleMessageListenerContainer wired with a POJO listener for RPC.
The template receiveAndReply method is intended for "scheduled" server-side RPC - i.e. only receive (and reply) when you want to, rather than whenever a message arrives in the queue. It does not block waiting for a message.
If you want to use receiveAndReply(), there's a test case that illustrates it.
EDIT:
This code...
this.template.convertAndSend(ROUTE, "test");
sends a message to the queue.
This code...
this.template.setQueue(ROUTE);
boolean received = this.template.receiveAndReply(new ReceiveAndReplyMessageCallback() {
#Override
public Message handle(Message message) {
message.getMessageProperties().setHeader("foo", "bar");
return message;
}
});
Receives a message and from that queue; adds a header and returns the same messsage to the reply queue. received will be false if there was no message to receive (and reply to).
This code:
Message receive = this.template.receive();
receives the reply.
This test is a bit contrived because the reply is sent to the same queue as the request. We can't use sendAndReceive() on the client side in this test because the thread would block waiting for the reply (and we need to execute the receiveAndReply()).
Another test in that class has a more realistic example where it does the sendAndReceive()s on different threads and the receiveAndReply()s on the main thread.
Note that that test uses a listener container on the client side for replies; that is generally no longer needed since the rabbit broker now supports direct reply-to.
receiveAndReply() was added for symmetry - in most cases, people use a listener container and listener adapter for server-side RPC.