I have integration test with docker using test containers. On container I run jms. In test I am putting message on queue.
How I can wait in test to make it populated on jms?
On local machine it works, but on jenkins it fails, so I have to add
Thread.sleep(3000);
but this is nasty.
org.awaitility seems to be missed usage:
await().atMost(2, TimeUnit.SECONDS).until(() -> return true));
I just need to do a pause to make jms propagate (put on jms queue) and wait for listener to act, which is putting message to database.
Then I have to call get rest endpoint to see it worked.
With topic it would be easier, because I would create test listener on topic.
But it is queue, there can be on listener that will get message.
Use org.awaitility with a JMS QueueBrowser, e.g.:
#Test
public void myTest() throws Exception {
...
await().atMost(2, TimeUnit.SECONDS).until(() -> return queueIsEmpty(queueName)));
...
}
private boolean queueIsEmpty(String queueName) {
ConnectionFactory cf = new MyBrokersConnectionFactory();
Connection connection = cf.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
QueueBrowser browser = session.createBrowser(session.createQueue(queueName));
Enumeration enumeration = senderBrowser.getEnumeration();
while (enumeration.hasMoreElements()) {
return false;
}
return true;
}
A QueueBrowser is read only so there is no danger that it will actually consume the message.
Another potential option would be to create a consumer with a transacted session and then try to receive the message. If you actually did receive a message you could rollback the transaction and close the consumer.
Use retries (e.g. Spring RetryTemplate or Failsafe Retry Policy) to improve integration test execution time:
Retry the SQL query until record is present
Retry the REST endpoint until it is successful
Here an example to wait for a DB record; tweak the policies to your needs:
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setBackOffPolicy(new FixedBackOffPolicy());
retryTemplate.setRetryPolicy(new SimpleRetryPolicy(
10, Collections.singletonMap(AssertionError.class, true)));
retryTemplate.execute(retryContext -> {
List<MyRecord> records = jdbcTemplate.query("select ...");
Assert.assertEquals(1, records.size());
return null;
});
My solution is to use org.awaitility lib and replace asserts with return statement:
await().atMost(30, TimeUnit.SECONDS).until(
() -> {
//
// assertTrue(condition);
return condition == true;
}
Related
we have a microservice which consumes a message using #RabbitListener and persist data into database, generate a response on successful processing of message and send it using #sendTO to different queue for auditing.
When running Rabbit in HA failover, while sending response if connection is lost the message currently being processed is correctly returned to the queue but database transaction (jpa transaction in our case) is not rolled back , response is never sent.
I read from this issue(https://github.com/spring-projects/spring-amqp/issues/696) that this is "best effort 1PC" transaction synchronization; RabbitMQ does not support XA transactions. The Rabbit tx is committed after the DB tx and there is a possibility the DB tx might commit and the rabbit rolled back; you have to deal with the small possibility of duplicate messages.
But in our case when we retry request, we are treating it as duplicate message and response is never created for this request. is there a way where we can only retry sending response message in case of connection lost exceptions rather than reprocessing request again? I looked at ConditionalRejectingErrorHandler.DefaultExceptionStrategy, it has access only to original request,no way to access response lost during connection failure. Please suggest what's the best way to handle this?
our code looks like:
SpringBootApplication
#EnableJpaRepositories("com.***")
#EnableJpaAuditing
#EnableTransactionManagement
#EnableEncryptableProperties
public class PcaClinicalValidationApplication {
#RabbitListener(queues = "myqueue"
#SendTo("exchange/routingKey")
#Timed) description = "Time taken to process a request")
public Message receivemessage(HashMap<String, Object> myMap, Message requestMessage)
throws Exception {
//business logic goes here
Message message = MessageBuilder.fromMessage(requestMessage)
//add some headers
return message;
}
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory,
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setRetryTemplate(new RetryTemplate());
factory.setReplyRecoveryCallback(ctx -> {
Message failed = SendRetryContextAccessor.getMessage(ctx);
Address replyTo = SendRetryContextAccessor.getAddress(ctx);
Throwable t = ctx.getLastThrowable();
//wrote to a file
serializer.serialize(failed);
return null;
});
return factory;
}
The listener container factory uses a RabbitTemplate in its replyTemplate property - this is used to send the reply.
You can configure a RetryTemplate into that RabbitTemplate to retry sending the reply.
When retries are exhausted, you can add a RecoveryCallback which will get the failed reply and you can save it off someplace and use it when the redelivery occurs.
I'm publishing messages into RabbitMQ and I would like to track the errors when RabbitMQ is down, for this I added one RetryTemplate with the recovery callback, but the recovery callback only provides this method getLastThrowable() and I'm not sure how to provide the details of the messages that failed when RabbitMQ is down. (as per documentation "The RecoveryCallback is somewhat limited in that the retry context only contains the
lastThrowable field. For more sophisticated use cases, you should use an external
RetryTemplate so that you can convey additional information to the RecoveryCallback via
the context’s attributes") but I don't know how to do that, if anyone could help me with one example that will be awesome.
Rabbit Template
public RabbitTemplate rabbitMqTemplate(RecoveryCallback publisherRecoveryCallback) {
RabbitTemplate r = new RabbitTemplate(rabbitConnectionFactory);
r.setExchange(exchangeName);
r.setRoutingKey(routingKey);
r.setConnectionFactory(rabbitConnectionFactory);
r.setMessageConverter(jsonMessageConverter());
RetryTemplate retryTemplate = new RetryTemplate();
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(500);
backOffPolicy.setMultiplier(10.0);
backOffPolicy.setMaxInterval(10000);
retryTemplate.setBackOffPolicy(backOffPolicy);
r.setRetryTemplate(retryTemplate);
r.setRecoveryCallback(publisherRecoveryCallback);
return r;
}
Recovery Callback
#Component
public class PublisherRecoveryCallback implements RecoveryCallback<AssortmentEvent> {
#Override
public AssortmentEvent recover(RetryContext context) throws Exception {
log.error("Error publising event",context.getLastThrowable());
//how to get message details here??
return null;
}
}
AMQP Outbound Adapter
return IntegrationFlows.from("eventsChannel")
.split()
.handle(Amqp.outboundAdapter(rabbitMqTemplate)
.exchangeName(exchangeName)
.confirmCorrelationExpression("payload")
.confirmAckChannel(ackChannel)
.confirmNackChannel(nackChannel)
)
.get();
The isn't possible because the function RabbitTemplate.execute() is already not aware about message you send, because it may be performed from any other method, where we might not have messages to deal:
return this.retryTemplate.execute(
(RetryCallback<T, Exception>) context -> RabbitTemplate.this.doExecute(action, connectionFactory),
(RecoveryCallback<T>) this.recoveryCallback);
What I suggest you to do is like storing message to the ThreadLocal before send and get it from there from your custom RecoveryCallback.
I am working with a legacy Windows Service that reads messages from a private MSMQ queue processes them (does some database work, sends some emails) and then waits for the next message (PeekCompleted)
The service is problematic - whenever Windows Update requires a server reboot (so like almost always) the Service comes back up in a "Started" condition but has to be REstarted manually or the messages just pile up in the queue.
My first inclination is to think that there is something in the OnStart handler that isn't getting hit when the server comes back up and I am attempting to sort out the Logs (another story) but Windows Services and threading are not my normal domain so I am hoping someone can point me in the right direction....
Below are the OnStart Handler and message handling function, stripped inconsequential stuff.
Question: in OnStart the MessageRecieved function is attached to the PeekCompleted event.
I assume OnStart fires when the server comes back up so the handler must get attached, but I am not clear whether message that were (a) already in the queue at re-boot or (b) arrive during re-boot will actually trigger the event ?
If it should is there something else I should be looking for?
Any suggestions welcome!
protected override void OnStart(string[] args)
{
try
{
_inProcess = false;
_queueMessage = null;
_stopping = false;
_queue = ReadyQueue(_queueName);
if (_queue == null)
{
throw new Exception(string.Format("'ReadyFormQueue({0})' returned null", _queueName));
}
_queue.PeekCompleted += new PeekCompletedEventHandler(MessageReceived);
_queue.Formatter = new BinaryMessageFormatter();
_queue.BeginPeek();
}
catch (Exception exception)
{
//do cleanup and other recovery stuff
}
}
private void MessageReceived(object sender, PeekCompletedEventArgs e)
{
_currentMessage = null;
_inProcess = false;
try
{
_queueMessage = _queue.EndPeek(e.AsyncResult);
_queueMessage.Formatter = new BinaryMessageFormatter();
_currentMessage = (MyMessageType)_queueMessage.Body;
_queue.ReceiveById(_queueMessage.Id);
_inProcess = true;
_helper = new MessageHelper();
_currentMessage = _helper.Process(_currentMessage); //sets global _inProcess flag
if (_inProcess)
{
Thread.Sleep((int)(_retryWaitTime * 0x3e8));
SendFormMessageToQueue(FailedQueueName, _currentMessage);
}
else
{
_queue.BeginPeek();
}
}
catch (Exception exception)
{
_inProcess = false;
//do other recovery stuff
if (_currentMessage != null)
{
ReadyFormQueue(_poisonQueueName);
SendFormMessageToQueue(_poisonQueueName, _currentMessage);
}
}
}
This legacy windows service could be started before the queueing infrastructure is up and fully operational, must fail in the initial connection and therefore isn't processing messages.
The first thing that I would check (unless the windows service has proper logging) is if there is a windows service dependency that is properly set up - you don't want your legacy service to fully start until the MSMQ service has itself completely started.
I don't think there is a problem in the legacy service per say since once you restart it, it seems to work fine, I think you have a resource-available-race type of problem where the consumer starts before the resource and it wasn't completely designed to recover from that.
I would: create a service dependency (can be done in the SCM) and then reboot the server and see if you have any more MSMQ messages pilling up, my guess the answer will be no.
Hope this helps
I have a Struts2 Action class that places a JMS Fetch request for a list of Trade in a JMS Queue. This JMS Fetch message is processed by an external process and can take either a few seconds or even few minutes depending on the number of Trade files to be processed by the external task processing app.
I want to know how to handle this HTTP Request with an appropriate response. Does the client wait till the list of Trades is returned? (client (UI) has to action on it and has nothing else to do meanwhile).
The way I approached it is
HTTP Request -->
Struts2 Action -->
Invokes a Runnable to run in a separate Thread (separate from Action class)
UI waits
Action class thread sleeps till runnable does it's job
When Task completed, return list of Trades to UI
Flow is as follows:
Place JMS Fetch Request on Queue1
ExecutorService for Runnable
CClass cclass = new CClass();
final ExecutorService execSvc = Executors.newFixedThreadPool(1);
execSvc.execute(cclass);
Where CClass implements runnable returning a list of Trades:
List<Trade> tradesList = new ArrayList<Trade>();
#Override
public void run() {
while (true) {
try {
Message message = msgConsumer.receive(); // SYNCHRONOUS / NO MDB
if (message == null){
break;
}
if (message instanceof TextMessage) {
TextMessage txtMessage = (TextMessage) message;
Trade trade = TradeBuilder.buildTradeFromInputXML(txtMessage);
if (trade != null) {
tradesList.add(trade); // tradeList is a CClass class variable
}
}
} catch (JMSException e) {
logger.error("JMSException occurred ", e);
}
}
closeConnection();
}
And while this runnableis executing, I do a Thread.sleep in Action class (to let the Runnable execute in the separate Thread)
// In Action class
try {
Thread.sleep(5000); // some time till when the runnable will get executed
} catch (InterruptedException e) {
e.printStackTrace();
}
execSvc.shutdown();
Problem is If I use Callable with a FutureTask and do a get() , that will be blocking till any result is returned. If I do a Runnable, I have to put Action class Thread to sleep till runnable has executed and tradeList is available.
Using Runnable approach, I am able to get couple of hundred records back to UI giving a 5 second Thread.sleep() in main Action class, but only partially constructed tradeList when thousands of records are to be fetched and shown in UI.
This is clearly Not a fail-proof approach.
Any better approach to suggest ? Please elucidate steps for processing in one complete request - response flow.
Yes there is a much better approach when making a standard HTTP request (with ajax you can do other things).
You want to look at the Struts2 Execute and Wait Interceptor Which has most of the functionality you've already implemented. Also look at the token interceptor... which could be useful (it prevents duplicate requests, but doesn't provide a happy wait screen like exec and wait does).
I am trying to make kind of a polling service towards a activemq queue using camel routes.
I am using routing and routing-jsm plugins for grails.
I have my route configuration set like this.
class QueueRoute {
def configure = {
from("activemq:daemon").routeId("daemonRoute")
.noAutoStartup()
.shutdownRunningTask(ShutdownRunningTask.CompleteCurrentTaskOnly)
.to('bean:daemonCamelService?method=receive')
.end()
}
}
and I am basically trying to do .suspendRoute("daemonRoute") and .resumeRoute("daemonRoute") with some time inbetween. Though after issuing suspendRoute the route is not stopped.
Anyone have tried this?, I have read something about needing to kill the exchange in progress or something similar.
if you are just trying to periodically process all messages in a queue, then another option (instead of starting and stopping the route) is to use a timer and a polling consumer bean to do retrieve all the messages in the queue...
from("timer://processQueueTimer?fixedRate=true&period=30000")
.to("bean:myBean?method=poll");
public class MyBean {
public void poll() {
// loop to empty queue
while (true) {
// receive the message from the queue, wait at most 3 sec
Object msg = consumer.receiveBody("activemq:queue:daemon", 3000);
if (msg == null) {
// no more messages in queue
break;
}
// send it to the next endpoint
producer.sendBody("bean:daemonCamelService?method=receive", msg);
}
}
}
See this FAQ how to stop/suspend a route from a route
http://camel.apache.org/how-can-i-stop-a-route-from-a-route.html
An alternative is to use a route policy
http://camel.apache.org/routepolicy
For example as we do with the throttling route policy that is provided out of the box, take a look at how its implemented, you can do similar for your route as well.