How can I get the processor to work asynchronously in inbound-endpoint in Mule? - asynchronous

I am new to Mule and i am working on a company project. I have many inbound-endpoints defined in XML in a single flow. I am trying to get the processor "scbProcessor" that processes the response to work asynchronously in the inbound-endpoint.
I tried to just wrap the processor in <async></async> but it gives the error: "Invalid content was found starting with element 'async'". Then I tried to make it sub-flow then reference to flow, which gave the same error.
Code:
<flow name="scb-services">
<composite-source doc:name="Composite Source inbounds">
<https:inbound-endpoint exchange-pattern="request-response" host="${httpInbound.secure.host}"
port="${httpInbound.secure.port}" doc:name="HTTPS QWE Service (Deprecated)"
path="${httpInbound.qwe.contextRoot}/${auto.external.serviceName}"
responseTimeout="${service.qwe.auto.timeout}" connector-ref="httpsConnector">
<mule-ss:http-security-filter realm="mule-realm"/>
<mule-ss:authorization-filter requiredAuthorities="PUBLIC"/>
<response>
<set-variable variableName="outgoingFromESBToClientDate"
value="#[new org.mule.el.datetime.DateTime()]"
doc:name="Register Outgoing date from ESB to Client"/>
<processor ref="scbProcessor" doc:name="SCB Logging Processor"/>
</response>
</https:inbound-endpoint>
.
.
</composite-source>
</flow>
.
.

You can change exchange-pattern="request-response" to exchange-pattern="one-way"to send the messages asynchronously. You can see it in the official documentation: https://docs.mulesoft.com/mule-runtime/3.6/http-transport-reference
Alternatively, you can use a queue in between. Send the message to queue as soon as it is received and then process it after reading it from the queue.

Related

MULE-4:VM: Check number of messages in VM queue before consuming

We required to consume messages from VM in a flow. Currently it is throwing an error when VM is empty as below:
Message : Tried to consume messages from VM queue 'FQ' but it was empty after timeout of 5 SECONDS Payload Type : org.mule.runtime.core.internal.streaming.bytes.ManagedCursorStreamProvider
For now we wrapped it in try catch block and handling this error(still it is printing the error stack trace, we want to avoid it)
I want to check is there a way or piece of code that can be used for checking the number of messages available in VM before consuming it.
You can use the logException attribute on the error handler so the exception is not printed in the log.
Example:
<try doc:name="Try">
<vm:consume doc:name="Consume" config-ref="VM_Config" queueName="q1" />
<error-handler >
<on-error-continue enableNotifications="true" logException="false" doc:name="On Error Continue" type="VM:EMPTY_QUEUE">
<logger level="INFO" doc:name="Logger" message="consume timeout"/>
</on-error-continue>
</error-handler>
</try>

Not able to send data on reply channel using tcp-outbound-gateway with ActiveMQ

My Requirement is to get data from TCP, after getting the data from TCP convert into java object and send on ActiveMQ. Post that after doing some processing need to send the acknowledgement/response code on same channel on TCP.
To fulfill this requirement I am using tcp-outbound-gateway as bidirectional communication is required.
Problem is I am not able to send acknowledgement with ActiveMQ. If I comment out ActiveMQ part and write a dummy string on replyChannel it is visible, but the moment I send the object on Active MQ queue it is giving me a message "null reply received for nothing to send".
I am using a new queue to get the acknowledgement and trying to put the response on reply channel of tcp-outbound-gate, but error message is no output-channel or replyChannel header available.
I got the MessageHeaders details via Incoming message and sending it via queue to use copyHeader. I am able to set the headers and see paylod in Message object, verified the same by applying Interceptos on reply channel, but still getting the same error no output-channel or replyChannel header available.
Code is :
<int:gateway id="gw" default-reply-channel="replyChannel" default-reply-timeout="10000" service-interface= "com.telnet.core.integration.connection.ParseTcpConfiguration$SimpleGateway"
default-request-channel="${server.inboundChannel}"/>
<int:channel id="telnetLandingChannel" />
<ip:tcp-connection-factory id="serverFactory" type="server" host="${server.host}" port="${server.port}" single-use="false"
serializer="${server.serializer}" deserializer="${server.serializer}" task-executor="serverFactoryTaskExecutor"/>
<ip:tcp-inbound-gateway id="serverInboundAdpater" request-channel="telnetLandingChannel" reply-channel="replyChannel"
connection-factory="serverFactory" error-channel="errorChannel" reply-timeout="1000000" auto-startup="false"/>
<int:channel id="replyChannel"></int:channel>
<beans:bean id="acknowledgementHandler" class= "com.telnet.core.integration.AcknowledgementHandler">
</beans:bean>
<int:channel id="incidentDispatchMessageChannel" datatype="${incident.interaction.dispatch.response.datatype}"></int:channel>
<int-jms:message-driven-channel-adapter id="incidentDispatchMessageChannelAdapter" error-channel="errorChannel"
connection-factory="mqConnectionFactory"
destination-name="${incident.processing.tcp.dispatch.response.queues}"
channel="incidentDispatchMessageChannel"/>
<int:transformer id="incidentMessageActivator"
input-channel="incidentDispatchMessageChannel"
output-channel="replyChannel"
ref="acknowledgementHandler" method="incidentAck">
</int:transformer>
public Message incidentAck(final DefaultIncidentAcknowledgeMessage defaultIncidentAcknowledgeMessage){
MessageHeaders ms = (MessageHeaders)defaultIncidentAcknowledgeMessage.getProperties().get("MessageHeader");
Message<String> message = MessageBuilder.withPayload("1").copyHeaders(ms).build();
return message;
}
Need to see your Integration configuration though, but let me guess that you are loosing TemporaryReplyChannel object in the replyChannel header because it isn't Serializable. Consider to use:
<int:header-enricher>
<int:header-channels-to-string/>
</int:header-enricher>
somewhere before sending to the ActveMQ.
See Reference Manual for more information.
UPDATE
Looks like this is a continuation of Receive the acknowledgement from TCP server to our application using spring Integration. And I see you still use the same replyChannel for many places. That isn't going to work properly. The replyChannel header from the gateway can accept only one reply. Even if we figure out what to do with the reply from ActiveMQ, the TemporaryReplyChannel will be fulfilled with the reply from the TCP Outbound Gateway.
If I understand you correctly, alongside with the reply from the TCP you need also get some message from ActiveMQ. And send everything as a reply to the gateway call. For this purpose I suggest you to consider to use Aggregator and figure out some custom correlation strategy to match the reply from TCP to that acknowledge from the ActiveMQ. After aggregation you really can just use the existing replyChannel header to reply to the gateway.

Get All Sales Order from Quick Book via QuickBook WebConnector using asp.net

I am using QuicBook Premier Edition UK , I have a company file open inside QuickBook. Build a sample WebService provided in samples and host in IIS. Added that application in WebConnector by using qwc file in samples.
I understood the callback methods required by WebConnector in soap service.
• authenticate
• clientVersion
• closeConnection
• connectionError
• getLastError
• receiveResponseXML
• sendRequestXML
I have tested web service by using WebConnector by using Update Selected button and it gives response 'OK' . But I am still confused how to get started with soap service , samples include 3 Xml request
CustomerQuery,
InvoiceQuery and
BillQuery .
How I test these request and see the response by using service . Can anyone explain the steps required to get me started with my own request of Get all Sales Order.
Thanks
Here is the screenshot
Here is the Last Output.
Version:
2.0.0.1
Message:
OK
Description:
Via closeConnection(): CloseConnection called to application.
Response received from application = OK
Explanation:
After calling authenticate(...), the Web Connector will call the sendRequestXML(...) method.
The sendRequestXML(...) method is essentially the Web Connector's way of saying "Hey, what do you want me to do?"
You should respond with a qbXML request telling QuickBooks/the Web Connector to do something. For example, if you are trying to get sales orders from QuickBooks, you could respond with a SalesOrderQuery qbXML request, something like this:
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="8.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<SalesOrderQueryRq requestID="2">
</SalesOrderQueryRq>
</QBXMLMsgsRq>
</QBXML>
The Web Connector will then send that request to QuickBooks, it will be processed, and the Web Connector will then call your receiveResponseXML(...) method.
The receiveResponseXML(...) method is essentially the Web Connector's way of saying "Hey, you told me to do something, I did it, and here's all of the data I got back: ... (big blob of XML from QuickBooks here)".
TLDR:
Return a qbXML request from the sendRequestXML method. A qbXML response will be sent to you in the receiveResponseXML method.
More notes:
Bigger explanation of the Web Connector here: http://www.consolibyte.com/docs/index.php/QuickBooks_Web_Connector_Overview
Lots of qbXML examples here: http://www.consolibyte.com/docs/index.php/Example_qbXML_Requests
Hundreds of pages of documentation in the QuickBooks SDK: https://developer.intuit.com/docs/0250_qb/0020_get_set_up/sdk_downloads

Mule ESB synchronous Until Successful payload modification

I've spent hours trying to solve my problem which seems to be caused by synchronous Until Successful Scope in Mule ESB v3.5.0. It seems to modify message payload when sending an outbound HTTP requests.
I need to continue in my flow after outbound HTTP request successfully returns from a HTTP server (which sometimes has connection problems). Thus I need the sync variant of Until Successful. For now I use just a simple Logger after the Until Successful block.
The body of my HTTP request is a XML file. When there is no problem at my server and the Until Successful doesn't need to make another HTTP request again, I receive the XML which I sent.
However, when there is a connectivity problem so the Until Successful repeats requesting a few times and then the server goes back online, on my server I receive an instance of org.apache.commons.httpclient.methods.PostMethod instead of the sent XML in the request body!
So no more XML on my server. It seems this sync Until Successful simply discards the original message payload...
The standard async variant of Until Successful works as intended - getting XML in requests all the time.
Here is a minimal sample of HTTP outbound endpoint with Until Successful:
<flow name="perform" doc:name="performHTTP">
<until-successful maxRetries="${repeater.retries}" millisBetweenRetries="${repeater.period}" failureExpression="#[exception != null && (exception.causedBy(java.net.ConnectException) || exception.causedBy(java.net.SocketTimeoutException)) || message.inboundProperties['http.status'] != 200]" doc:name="Until Successful - Repeater" synchronous="true">
<http:outbound-endpoint exchange-pattern="request-response" host="${https.outbound.address}" port="${https.outbound.port}" path="${https.outbound.path}" method="POST" mimeType="text/xml" transformer-refs="Custom_Outbound_HTTPS_Header" contentType="text/xml" doc:name="HTTPS - Outbound" doc:description="Outcoming HTTPS connection" responseTimeout="15000"/>
</until-successful>
<logger message="#['Sending done']" level="INFO" doc:name="Logger - Done"/>
</flow>
Long story short:
synchronous Until Successful: XML -> HTTP request - { NET } - HTTP request -> org.apache.commons.httpclient.methods.PostMethod
asynchronous Until Successful: XML -> HTTP request - { NET } - HTTP request -> XML
I had the same problem and fixed it by saving my payload and retrieving on each retry something like this
<set-variable value="#[payload]" variableName="paloadbeforecall" doc:name="Variable" />
<until-successful maxRetries="${repeater.retries}" millisBetweenRetries="${repeater.period}" failureExpression="#[exception != null && (exception.causedBy(java.net.ConnectException) || exception.causedBy(java.net.SocketTimeoutException)) || message.inboundProperties['http.status'] != 200]" doc:name="Until Successful - Repeater" synchronous="true">
<processor-chain>
<set-payload value="#[flowVars.?paloadbeforecall]" doc:name="Variable" />
<http:outbound-endpoint exchange-pattern="request-response" host="${https.outbound.address}" port="${https.outbound.port}" path="${https.outbound.path}" method="POST" mimeType="text/xml" transformer-refs="Custom_Outbound_HTTPS_Header" contentType="text/xml" doc:name="HTTPS - Outbound" doc:description="Outcoming HTTPS connection" responseTimeout="15000"/>
</processor-chain>
</until-successful>
Sounds like a bug. It would be interesting to report this as an issue. Anyhow, there is a simple workaround for this, just wrap the until-successful in a wire-tap. This will create a copy of the message (not necessarily the payload) and given that the payload is inmmutable (String) the oubound-endpoint will just change the reference without affecting the flow after the wire-tap.

How to configure Rebus manualy to use external server

I've got a app.config configuration for Rebus and it works:
<configuration>
<configSections>
<section name="rebus" type="Rebus.Configuration.RebusConfigurationSection, Rebus" />
</configSections>
<rebus address="192.168.10.100" inputQueue="a.messages" errorQueue="a.error" workers="1" maxRetries="10">
<endpoints>
<add messages="ESB_Model" endpoint="a.messages#MyRemoteMachine" />
</endpoints>
</rebus>
</configuration>
After now I want to set the address and endpoint in code instead of configfile:
_adapter = new BuiltinContainerAdapter();
_bus = Configure.With(_adapter)
.Logging(l => l.None())
.Transport(t => t.UseMsmq("a.messages#MyRemoteMachine", "a.error"))
.MessageOwnership(d => d.FromRebusConfigurationSection())
.CreateBus()
.Start();
This is not accepted and I'm not sure how to set the IP-address. Any help would be welcome!
I can see a couple of issues with your code, first one being that the two configurations are not equivalent.
The issue with the second configuration is that Rebus does not allow you to use a remote queue as your endpoint's input queue. Therefore, the #-syntax should not be used when defining the input queue.
Also, it seems you're mixing something up - a.messages seems to be your input queue, but it also seems that you want to use it (granted: on another machine) as the owner of all messages from ESB_Model. It might be correct, but it seems you're mixing it up a little bit.
Usually, each endpoint should have its own unique input queue, and endpoints should always receive their messages from a local queue. And you should probably never have two endpoints receiving messages from the same queue.
Lastly: Unless you really know what you're doing, please don't explicitly specify the IP address of your endpoint - Rebus will automatically use the input queue in combination with the machine name as the address - e.g. if an endpoint a.messages running on SomeMachine sends a message to another endpoint, the return address will automatically be set as a.messages#SomeMachine.
If you'd like some more inspiration, you can check out the samples: https://github.com/mookid8000/Rebus/tree/master/samples/Rebus.Samples - the pub/sub sample has some simple configurations that work fine and don't over-specify.
Hope that clears it up a little bit - please let me know if you need more help :)

Resources