I encapsulated JCSMP API in a class and provide methods for other classes to send and consume messages.
I have the following method:
public void send(byte[] data, String queueName) throws JCSMPException {
// Acquire a message producer
if (producer == null) { //producer is an instance of XMLMessageProducer
producer = session.getMessageProducer(new PublishCallback());
}
Queue queue = JCSMPFactory.onlyInstance().createQueue(queueName);
BytesMessage msg = JCSMPFactory.onlyInstance().createMessage(BytesMessage.class);
msg.setData(data);
msg.setDeliveryMode(DeliveryMode.PERSISTENT);
logger.info("Sending to \"{}\"", queueName);
producer.send(msg, queue);
}
When I have multiple threads calling this method, once in a while, I notice the following exception:
com.solacesystems.jcsmp.ClosedFacilityException: Tried to perform operation on a closed XML message producer
I wonder whether the producer is closed after each call to send(). How should I make this method thread-safe?
Thank you.
XMLMessageProducer does not close itself after each call to send.
The first step here is to investigate why your XMLMessageProducer is closed. The easiest option to do this is to enable the Solace API logging to INFO (or even DEBUG), and edit your question to include the Solace API logs prior to the first ClosedFacilityException.
One possible reason is that your application has disconnected, but was not able to automatically reconnect to the Solace appliance/VMR.
Related
I'm trying to create a Flux from incoming messages received from a queue.
For instance, if I'm using Amazon SQS how do I achieve to write the following code:
Flux<String> messages = connectionToSQS.receiveFromQueue(queueName);
messages.map(s -> log.info("message: {}", s).subscribe();
After experimentation, I found the following issues:
How do I keep requesting messages from the queue (loop forever)? Do I create one thread that has a loop that keeps on requesting from the queue?
How do I make the Flux cold? I don't want to request messages from SQS unless the consumer asks for it. This allows me to use backpressure.
First pass over this problem yielded something like the following code as per Reactor documentation:
Flux<String> bridge = Flux.create(sink -> {
myEventProcessor.register(new MyEventListener<String>() {
public void onDataChunk(List<String> chunk) {
for(String s : chunk) {
sink.next(s);
}
}
public void processComplete() {
sink.complete();
}
});
});
The idea being to create a single thread that keeps on requesting for messages in a loop and then using an observer pattern like above to do a next() on each message received.
I have one resque job which is run at some event which finally publishes the message to RabbitMQ's exchange, how can I check in bunny(Rabbit MQ ruby client) that whether the message has been successfully published?
Using Acknowledgment or any way?
Thanks in advance!
When you execute the publish you are not sure that the message is published on the queue.
If you want to be sure you have to use you have to use publish confirm or tx transaction.
Read this post http://www.rabbitmq.com/blog/2011/02/10/introducing-publisher-confirms/
Note: By default the clients don't have any HA policy, you have to implement it. See the section Streaming Lightweight Publisher Confirms:
private volatile SortedSet<Long> unconfirmedSet =
Collections.synchronizedSortedSet(new TreeSet());
...
ch.setConfirmListener(new ConfirmListener() {
public void handleAck(long seqNo, boolean multiple) {
if (multiple) {
unconfirmedSet.headSet(seqNo+1).clear();
} else {
unconfirmedSet.remove(seqNo);
}
}
public void handleNack(long seqNo, boolean multiple) {
// handle the lost messages somehow
}
});
Note2: the message is never "put" inside an exchange, but always inside a queue.
Once the publish method returns, the message has published to the queue. There is no deferred action to publishing a message.
I need to implement a listener that receives multiple messages then groups them base on a certain criteria then send the grouped messages to the next queue. In other words batching them in a logical way.
I'm using Grails and JMS integration plugin.
In my mind, it can be implemented in a listener that runs a single thread that runs an infinite loop that forever consume messages from a queue then do the grouping logic there.
Runnable runnable = new Runnable() {
#Override
public void run() {
while(true) {
def obj = consumer.receive()
//group the messages and store on a list then send them in groups to the next queue
producer.send(groupedObjList)
}
}
}
def thread = new Thread(runnable);
thread.start();
I'm not sure if this is a clean way to do it. So I'm looking for alternatives on how to implement this.
I am using spring amqp publishing my messages to RabbitMQ using an outbound gateway. I have set publisher confirms on the connection factory and added my custom callback listener.
The problem is that my CorrelationData is always null and i can't add any correlation data on an outbound gateway. This is only applicable for an outbound channel adapter.
For an outbound gateway will publisher confirms even work?
EDIT
My configuration is below. I looked through the SI code and yes, publisher confirms, are enabled. The problem is what I do when I receive a NACK?
Because of the outbound gateway I don't need a correlation id to handle the response, there is already a thread listening on a temporary reply queue for the response.
What exactly is the point of using publisher confirms with an outbound gateway? If no response is coming or my Rabbit nodes go down I will encounter exceptions. Is there a scenario when I will lose messages?
<rabbit:connection-factory id="rabbitConnectionFactory"
host="someip" port="5672"
username="username"
password="password"
virtual-host="vhost"
publisher-confirms="true"/>
<rabbit:admin connection-factory="rabbitConnectionFactory"/>
<rabbit:template id="amqpTemplate" connection-factory="rabbitConnectionFactory"
confirm-callback="messagesConfirmCallback"/>
<int-amqp:outbound-gateway
request-channel="channel"
amqp-template="amqpTemplate"
exchange-name="exchange"
routing-key-expression="headers['queueSpecific']+'.queue'">
<amqp:request-handler-advice-chain>
<ref bean="retryAdvice"/>
</amqp:request-handler-advice-chain>
</int-amqp:outbound-gateway>
And my callback is also simple
#Component
public class MessagesConfirmCallback implements RabbitTemplate.ConfirmCallback {
private final static Logger LOGGER = LoggerFactory.getLogger(MessagesConfirmCallback.class);
#Override
public void confirm(CorrelationData correlationData, boolean ack) {
if(ack){
LOGGER.info("ACK received");
}
else{
LOGGER.info("NACK received");
}
}
}
This
Unfortunately, I don't see an easy work around with the gateway; the underlying RabbitTemplate only supports adding correlation data on send() methods, not the sendAndReceive methods.
The two options I can think of is to (1) use a pair of outbound and inbound adapters (instead of the gateway), but you'll have to do your own request/reply correlation in that case.
Alternatively (2), use the RabbitTemplate.execute() and in the doInRabbit callback, add code similar to that in the RabbitTempalate.doSendAndReceive, while setting the correlation data as is done in doSend().
I opened a JIRA Issue.
After complete of asynchronous call to WCF service I want set success message into session and show user the notification .
I tried use two ways for complete this operation.
1) Event Based Model.
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(GetDataCompleted);
client.GetDataAsync(id, client);
private void GetDataCompleted(object obj, GetDataCompletedEventArgs e)
{
this.SetNotification(new Notification() { Message = e.Result, Type = NotificationType.Success });
}
In MyOperationCompleted event i can set notification to HttpContext.Current.Session, but I must waiting before this operation will completed and can't navigate to others pages.
2) IAsyncResult Model.
In this way I can navigate to other pages and make asynchronous calls to wcf service, but in GetDataCallback method can't set notification, becouse session = null.
client.BeginGetData(id, GetDataCallback, client);
private void GetDataCallback(IAsyncResult ar)
{
string name = ((ServiceReference1.Service1Client)ar.AsyncState).EndGetData(ar);
this.SetNotification(new Notification() { Message = name, Type = NotificationType.Success });
}
"Generate asynchronous operations" in service reference enabled.
Please help me with this trouble. Thanks.
I'm no wcf expert, but what I've found to work is wrapping your call to the Async version of your method in ThreadPool.QueueUserWorkItem. Without this, I had same blocking issue. So this seems to free up the main thread in your asp mvc to move on while another worker thread waits for the callback.
Also, I used AsyncController, although that alone was not enough without the worker thread.
See this: http://msdn.microsoft.com/en-us/library/ee728598.aspx
I used this as a guide, but still needed the ThreadPool.
Cheers