from(jetty).bean(RequestProcessor).to(netty).bean(ResponseProcessor)
In above route, the netty endpoint can return messages in any order based on downstream latency. Eg., The messages arrive in the order msg1, msg2 and sent over netty. Netty can receive messages in the order msg2, msg1.
How do we correlate messages in the above route ? What will be Exchange.CORRELATION_ID, when message arrives at ResponseProcessor ?
How do we reply to correct http request ?
Related
I have a Camel client using the JMS Component to connect with IBMMQ.
I need to
Send a JMSCorrelationID with a fixed value.
Correlate the Reply message by JMSMessageID.
My configuration is:
.setHeader("CamelJmsDestinationName", "queue:///requestQueue.AQ?targetClient=1")
.setHeader("JMSCorrelationID", "SomeValue")
.to("jms:queue:requestQueue.AQ?useMessageIDAsCorrelationID=true&replyTo=ResponseQueue")
The issue is that JMSCorrelationID is null when useMessageIDAsCorrelationID=true
JMSMessageID: ID:c3e2d840d8d4e3f14040404040404040d95c7873193bef06
JMSTimestamp: 1614870096440
JMSCorrelationID: null
When useMessageIDAsCorrelationID=false the JMSCorrelationID is set as intended, but I get a timeout on correlation. How to use both?
As a way around the issue I made the following changes to the .to() endpoint options:
exchangePattern=InOnly
includeSentJMSMessageID=true
Then the message is sent with a JMSCorrelationID, but without waiting on the reply. Thereafter I set a pollEnrich() dynamically with a simple expression using the JMSMessageID created by the broker which is filtered by a JMS Selector:
selector=JMSMessageID='${header.JMSMessageID}
The Camel route:
.setHeader("CamelJmsDestinationName", "queue:///requestQueue.AQ?targetClient=1")
.setHeader("JMSCorrelationID", "SomeValue")
.to("jms://RequestQueue?useMessageIDAsCorrelationID=false&exchangePattern=InOnly&replyTo=ReplyQueue&includeSentJMSMessageID=true")
.pollEnrich().simple("jms://ReplyQueue?selector=JMSMessageID='${header.JMSMessageID}').timeout(20000)
.log("${body}")
I have an application that receives a HL7 message and sends back an acknowledgement response. I'm using Citrus with the Camel MLLP component to send this HL7 message. What I'm trying to achieve is to be able to read the acknowledgement to compare it.
I currently have a test with hl7Payload, a String variable with HL7 content. In my Citrus context I have:
<citrus-camel:sync-endpoint id="mllpOutEndpoint"
camel-context="mllpContext"
endpoint-uri="mllp:localhost:6662"/>
I tried extracting the header I found on the Camel documentation:
send("mllpOutEndpoint")
.fork(true)
.messageType(MessageType.PLAINTEXT)
.payload(hl7Payload)
.extractFromHeader("CamelMllpAcknowledgementString", "receivedAck");
echo("${receivedAck}");
But I get this error:
com.consol.citrus.exceptions.UnknownElementException: Could not find header element CamelMllpAcknowledgementString in received header
Everything works fine without extractFromHeader(). The application receives my HL7 message, sends back an ACK and the test passes, but I'm struggling to get this ACK content back to make further tests. What am I missing here?
I got it:
async().actions(
send("mllpOutEndpoint")
.messageType(MessageType.PLAINTEXT)
.payload(hl7Payload),
receive("mllpOutEndpoint")
.header("CamelMllpAcknowledgementType", "AA")
);
Below I am trying to execute the STOMP commands via netcat and when I try to get a receipt for the first message I receive the 2nd message unexpectedly (a RECEIPT and MESSAGE) when I only expected a RECEIPT to come back from the server. The below commands are executed with 4 messages on the queue. Please advise.
Sent to server
CONNECT
login: sender_receiver
passcode:sender_receiver
accept-version:1.2
^#
From the server
CONNECTED
server:ActiveMQ/5.15.4
heart-beat:0,0
session:ID:centos7-42009-1529845487133-3:5
version:1.2
Sent to the server
SUBSCIBE
destination:/queue/queueName
activemq.prefetchSize:1
ack:client
id:12345
^#
Received from server
MESSAGE
content-length:9
expires:0
destination:/queue/queueName
ack:ID\ccentos7-42009-1529845487133-14\c1
subscription:12345
priority:4
redelivered:true
message-id:ID\ccentos7-42009-1529845487133-3\c4\c-1\c1\c1
persistent:true
timestamp:1529845914578
message 0
Sent to server
ACK
receipt:ack_id_receipt
id:ID\ccentos7-42009-1529845487133-14\c1
^#
Received from server
RECEIPT
receipt-id:ack_id_receipt
MESSAGE
content-length:9
expires:0
destination:/queue/queueName
ack:ID\ccentos7-42009-1529845487133-16\c2
subscription:12345
priority:4
message-id:ID\ccentos7-42009-1529845487133-3\c10\c-1\c1\c2
persistent:true
timestamp:1529863616319
message 1
I have a camel route which will be throttled on recieving loads of messages. Suppose the maximum exchanges i defined is 3 per 2 seconds and the route recieves more than the limit i want to redirect those messages to some other load balancer route. Can someone help me how to achieve it??
If I am understanding your question right you want to throttle your incoming messages then loadbalance those messages out to a different route or system.
from("SomethingSendingMeMessages")
.throttle(3)
.loadbalance().roundRobin()
.to("place1", "place2", "place3")
.end();
If you need to have the throttling route send to a second route that contains the loadbalancer you can do it like follows:
from("SomethingSendingMeMessages")
.throttle(3)
.to("direct:mySecondRoute");
from("direct:mySecondRoute")
.loadbalance().roundRobin()
.to("place1", "place2", "place3")
.end();
Another option you could explore is throttling after the loadbalancer to control each individual route's method.
from("SomethingSendingMeMessages")
.loadbalance().roundRobin()
.to("direct:place1", "direct:place2")
.end();
from("direct:place1")
.throttle(3)
.to("myOtherWork");
from("direct:place2")
.throttle(3)
.to("myOtherWork");
I have a requirement which is as follows:
Accept HTTP POST requests containing XML to a certain URL.
Perform pre-requisite actions such as saving the request XML to a file.
Validate the incoming XML matches the corresponding schema.
If the schema validation fails, synchronously respond with a HTTP 400 response code.
If the schema validation passes, synchronously respond with a HTTP 200 response code.
Pass the XML message on for further processing.
When this further processing completes, asynchronously respond to the caller with a HTTP 200 response code.
This is currently how I have the route configured:
onException(IOException.class)
.log(LoggingLevel.INFO, "Schema validation error on incoming message: ${id}")
.handled(true)
.maximumRedeliveries(0)
.process(schemaValidationErrorProcessor);
from("restlet:http://localhost:" + portNum + "/api/XX/XXX?restletMethod=POST")
.log(LoggingLevel.INFO, "Received message")
.convertBodyTo(String.class)
.multicast()
.parallelProcessing()
.to(SAVE_REQUEST_TO_FILE_QUEUE, PROCESS_PROVISIONING_REQUEST_QUEUE);
from(SAVE_REQUEST_TO_FILE_QUEUE)
.log(LoggingLevel.INFO, "Storing message: ${id}")
.to("file://" + requestLogFolder);
from(PROCESS_PROVISIONING_REQUEST_QUEUE)
.log(LoggingLevel.INFO, "Processing provisioning request: ${id}")
.process(requestGate)
.choice()
.when(header(SYSTEM_STATUS_HEADER).isEqualTo(true))
.unmarshal(xmlParser)
.inOnly("bean:requestHandler?method=handle")
.when(header(SYSTEM_STATUS_HEADER).isEqualTo(false))
.log(LoggingLevel.INFO, "Intentially dropping message")
.endChoice();
The schema validation part is achieved via the .unmarshal(xmlParser) line (I have a JaxbDataFormat object configured elsewhere with the schema set in that). When schema validation fails, an IOException is thrown and this is handled by my schemaValidationErrorProcessor which adds the HTTP 400 to the response.
That is all working fine.
The problem I am having is passing the XML message on for further processing. Basically, I need this to be done asynchronously because when the schema validation passes I need to synchronously respond with a 200 response. The processing that I need to do is in the .inOnly("bean:requestHandler?method=handle") line.
I naively thought that setting the routing to my bean to inOnly would set this to be asynchronous and that main route would not wait for a response. However, this is not the case as when the requestHandler.handle method throws an exception, this is thrown back to the caller of the REST endpoint. I don't want this to happen as I want all of this processing to be done in 'the background' as the consumer will have already received a 200 response.
So, my question is, how would I go about achieving such behaviour? I have thought about using queues etc but ideally would like to avoid such components if possible.
Use Camel Websocket component for asynchronously respond to the caller.
From the Camel documentation:
from("activemq:topic:newsTopic")
.routeId("fromJMStoWebSocket")
.to("websocket://localhost:8443/newsTopic?sendToAll=true&staticResources=classpath:webapp");