How to check number of pending messages or all messages are processed or not in ActiveMQ using mule flow - activemq

I have a requirement to stop the ActiveMQ connector if all messages have been processed in the queue. This needs to be done in Mule flow.
As shown below, I have two connectors one for reading and other for writing on vci.staging.queue. I want to check if all messages are processed in the queue then disable the reader connector.
Below piece of script to use client.request from muleContext using queue name and reader or writer connector is always returning ‘null’ for me.
Is there any way to get number of pending messages in a queue or to check if all messages are processed or not so that connector can be disabled?
<jms:activemq-connector name="jmsConnectorStagingQReaderNormal"
brokerURL="${mule.activemq.broker.read.normal.url}"
specification="1.1"
maxRedelivery="-1"
persistentDelivery="true"
numberOfConcurrentTransactedReceivers="${mule.activemq.concurrent.receivers}"
connectionFactory-ref="connectionFactory"
disableTemporaryReplyToDestinations="false">
</jms:activemq-connector>
<jms:activemq-connector name="jmsConnectorStagingQWriter"
brokerURL="${mule.activemq.broker.write.url}"
specification="1.1"
maxRedelivery="-1"
persistentDelivery="true"
numberOfConcurrentTransactedReceivers="${mule.activemq.concurrent.receivers}"
connectionFactory-ref="connectionFactory"
disableTemporaryReplyToDestinations="false">
</jms:activemq-connector>
<script:component>
<script:script engine="groovy">
if(muleContext.getRegistry().lookupConnector('jmsConnectorStagingQReaderNormal').isStarted()) {
if(muleContext.client.request("jms://vci.staging.queue?connector= jmsConnectorStagingQReaderNormal ", 5000) == null) {
muleContext.getRegistry().lookupConnector('jmsConnectorStagingQReaderNormal').stop()
}
}
return payload
</script:script>
</script:component>

Use a QueueBrowser to peek into a JMS queue without consuming its messages.
For this:
Create a custom component,
Have Spring inject your jms:activemq-connector in the component,
Call getSession(false, false) on it to get an active JMS Session,
Call createBrowser(Queue queue) on the Session (you can get a hold of the Queue with Session.createQueue(..).

Related

Anypoint MQ messages remains in in-flight and not been processed

I have a flow which submits around 10-20 salesforce bulk query job details to anypoint mq to be processed asynchronously.
I am using normal Queue, Not using FIFO queue and wants process one message at a time.
My subscriber configurations are given below. I am putting this whooping ack timeout to 15 minutes as max it has taken 15 minutes for a Job to change the status from jobUpload to JobCompleted.
MuleRuntime: 4.4
MQ Connector Version: 3.2.0
<anypoint-mq:subscriber doc:name="Subscribering Bulk Query Job Details"
config-ref="Anypoint_MQ_Config"
destination="${anyPointMq.name}"
acknowledgementTimeout="15"
acknowledgementTimeoutUnit="MINUTES">
<anypoint-mq:subscriber-type >
<anypoint-mq:prefetch maxLocalMessages="1" />
</anypoint-mq:subscriber-type>
</anypoint-mq:subscriber>
Anypoint MQ Connector Configuration
<anypoint-mq:config name="Anypoint_MQ_Config" doc:name="Anypoint MQ Config" doc:id="ce3aaed9-dcba-41bc-8c68-037c5b1420e2">
<anypoint-mq:connection clientId="${secure::anyPointMq.clientId}" clientSecret="${secure::anyPointMq.clientSecret}" url="${anyPointMq.url}">
<reconnection>
<reconnect frequency="3000" count="3" />
</reconnection>
<anypoint-mq:tcp-client-socket-properties connectionTimeout="30000" />
</anypoint-mq:connection>
</anypoint-mq:config>
Subscriber flow
<flow name="sfdc-bulk-query-job-subscription" doc:id="7e1e23d0-d7f1-45ed-a609-0fb35dd23e6a" maxConcurrency="1">
<anypoint-mq:subscriber doc:name="Subscribering Bulk Query Job Details" doc:id="98b8b25e-3141-4bd7-a9ab-86548902196a" config-ref="Anypoint_MQ_Config" destination="${anyPointMq.sfPartnerEds.name}" acknowledgementTimeout="${anyPointMq.ackTimeout}" acknowledgementTimeoutUnit="MINUTES">
<anypoint-mq:subscriber-type >
<anypoint-mq:prefetch maxLocalMessages="${anyPointMq.prefecth.maxLocalMsg}" />
</anypoint-mq:subscriber-type>
</anypoint-mq:subscriber>
<json-logger:logger doc:name="INFO - Bulk Job Details have been fetched" doc:id="b25c3850-8185-42be-a293-659ebff546d7" config-ref="JSON_Logger_Config" message='#["Bulk Job Details have been fetched for " ++ payload.object default ""]'>
<json-logger:content ><![CDATA[#[output application/json ---
payload]]]></json-logger:content>
</json-logger:logger>
<set-variable value="#[p('serviceName.sfdcToEds')]" doc:name="ServiceName" doc:id="f1ece944-0ed8-4c0e-94f2-3152956a2736" variableName="ServiceName"/>
<set-variable value="#[payload.object]" doc:name="sfObject" doc:id="2857c8d9-fe8d-46fa-8774-0eed91e3a3a6" variableName="sfObject" />
<set-variable value="#[message.attributes.properties.key]" doc:name="key" doc:id="57028932-04ab-44c0-bd15-befc850946ec" variableName="key" />
<flow-ref doc:name="bulk-job-status-check" doc:id="c6b9cd40-4674-47b8-afaa-0f789ccff657" name="bulk-job-status-check" />
<json-logger:logger doc:name="INFO - subscribed bulk job id has been processed successfully" doc:id="7e469f92-2aff-4bf4-84d0-76577d44479a" config-ref="JSON_Logger_Config" message='#["subscribed bulk job id has been processed successfully for salesforce " ++ vars.sfObject default "" ++ " object"]' tracePoint="END"/>
</flow>
After the bulk query job subscriber, I am checking the status of the job for 5 time with an interval of 1 minutes inside until successful scope. It generally exhausts all 5 attempts and subscribe it again and do the same process again until it gets completed. I have seen until successfull scope gets exhausted more than one for a single job.
Once the job's status changes to jobComplete. I fetch the result and sends to AWS S3 bucket via mulesoft system api. Here also I use a retry logic as due to large volume of data I always get this message while making first call
HTTP POST on resource 'https://****//dlb.lb.anypointdns.net:443/api/sys/aws/s3/databricks/object' failed: Remotely closed.
But during the second retry it gets successful response from S3 Bucket system api.
Now the main problem:
Though I am using normal queue. I have notice messages remains in flight mode for infinite amount of time and still not get picket up by mule flow/subscriber. Below screenshot shows an example, there were 7 messages in flight but were not being picked up even after many days.
As I have kept maxConcurrency and maxPrefetchLocalMsg to 1. But there are more than 1 messages are been taken out of the queue. Please help understand this.

Mule ActiveMQ at particular time interval

I have a scenario wherein I need to start receiving messages from Queue after a particular time interval irrespective of time the message is placed in queue.
For example Flow A process some service calls and then place the below message in queue
{
filename:"blahblah.pdf"
}
Now Flow B need to start recieving the messages from queue after 9PM(or some time) daily and then process it.
I wonder is it possible to achieve this scenario in Mule.
You can achieve this in Mulesoft using Poll Scope or Quartz Schedular.
Code will be some thing like
<quartz:inbound-endpoint jobName="ReadQIN"
cronExpression="* * * * * ?" doc:name="Quartz">
<quartz:endpoint-polling-job>
<quartz:job-endpoint address="jms://QIN" />
</quartz:endpoint-polling-job>
</quartz:inbound-endpoint>

Read messages from DLQ in Jboss 7

I have below two jms queues configured in JBOSS 7.1.
<jms-queue name="APP.QUEUE1">
<entry name="queue/APP.QUEUE1"/>
<entry name="java:jboss/exported/jms/queue/APP.QUEUE1"/>
</jms-queue>
<jms-queue name="APP.QUEUE2">
<entry name="queue/APP.QUEUE2"/>
<entry name="java:jboss/exported/jms/queue/APP.QUEUE2"/>
</jms-queue>
while consuming the message, if some thing goes wrong then the message will go to Dead letter Queue that is configured as follows.
<address-setting match="jms.queue.APP#">
<dead-letter-address>jms.queue.DLQ</dead-letter-address>
<expiry-address>jms.queue.ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<max-delivery-attempts>5</max-delivery-attempts>
<max-size-bytes>10485760</max-size-bytes>
<address-full-policy>BLOCK</address-full-policy>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
</address-setting>
so I have successfully delivered the message to DLQ.
Now I have written consumer for Dead letter queue, so that I can transfer back the message after fixing the issue.
the piece of code to consume the message is as follows.
QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueBrowser browser = session.createBrowser(queue);
Queue queue1=browser.getQueue();
Enumeration messageEnum = browser.getEnumeration();
while (messageEnum.hasMoreElements()) {
TextMessage message = (TextMessage) messageEnum.nextElement();
}
from the text message,is there any chance of getting source queue (APP.QUEUE1 or APP.QUEUE2), so that I have transfer back the same text message with out worrying much on message properties.
please let me know my approach is correct or not,appricite for better solution.
Found the answer for this.
we have property as follows.
message.getStringProperty("_HQ_ORIG_ADDRESS");
This property give originating address.

In RabbitMQ how to consume multiple message or read all messages in a queue or all messages in exchange using specific key?

I want to consume multiple messages from specific queue or a specific exchange with a given key.
so the scenario is as follow:
Publisher publish message 1 over queue 1
Publisher publish message 2 over queue 1
Publisher publish message 3 over queue 1
Publisher publish message 4 over queue 2
Publisher publish message 5 over queue 2
..
Consumer consume messages from queue 1
get [message 1, message 2, message 3] all at once and handle them in one call back
listen_to(queue_name , num_of_msg_to_fetch or all, function(messages){
//do some stuff with the returned list
});
the messages are not coming at the same time, it is like events and i want to collect them in a queue, package them and send them to a third party.
I also read this post:
http://rabbitmq.1065348.n5.nabble.com/Consuming-multiple-messages-at-a-time-td27195.html
Thanks
Don't consume directly from the queue as queues follow round robin algorithm(an AMQP mandate)
Use shovel to transfer the queue contents to a fanout exchange and consume messages right from this exchange. You get all messages across all connected consumers. :)
If you want to consume multiple messages from specific queue, you can try as below.
channel.queueDeclare(QUEUE_NAME, false, false,false, null);
Consumer consumer = new DefaultConsumer(channel){
#Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
logger.info("Recieved Message --> " + message);
}
};
You might need to conceptually separate domain-message from RMQ-message. As a producer you'd then bundle multiple domain messages into a single RMQ-message and .produce() it to RMQ. Remember this kind of design introduces timeouts and latencies due to the existence of a window (you might take some impression from Kafka that does bundling to optimize I/O at the cost of latency).
As a consumer then, you'd have a consumer, with typical .handleDelivery implementation that would transform the received body for the processing: byte[] -> Set[DomainMessage] -> your listener.

Query for Number of Messages in Mule ESB VM Queue

In a Mule flow, I would like to add an Exception Handler that forwards messages to a "retry queue" when there is an exception. However, I don't want this retry logic to run automatically. Instead, I'd rather receive a notification so I can review the errors and then decide whether to retry all messages in the queue or not.
I don't want to receive a notification for every exception. I'd rather have a scheduled job that runs every 15 minutes and checks to see if there are messages in this retry queue and then only send the notification if there are.
Is there any way to determine how many messages are currently in a persistent VM queue?
Assuming you use the default VM queue persistence mechanism and that the VM connector is named vmConnector, you can do this:
final String queueName = "retryQueue";
int messageCount = 0;
final VMConnector vmConnector = (VMConnector) muleContext.getRegistry()
.lookupConnector("vmConnector");
for (final Serializable key : vmConnector.getQueueProfile().getObjectStore().allKeys())
{
final QueueKey queueKey = (QueueKey) key;
if (queueName.equals(queueKey.queueName))
{
messageCount++;
}
}
System.out.printf("Queue %s has %d pending messages%n", queueName, messageCount);