I am looking for a way to aggregate JMS messages sent from multiple application servers, load-balanced via JMS. The problem is basically this:
At the end of our registration form, there exists a container in the http session, and the container has two objects of the same type. Each object needs to be processed, then the container needs to be delivered. Processing an object is resource intensive, so the processing is requested (InOnly, asynchronous) and queued up in OpenMQ. The JMS message is consumed by one of two competing consumers, that are basically duplicate application servers, that also serve up the web requests.
Currently, I just have a hard-coded delay on the container delivery, but with increased traffic there are plenty of delivery failures, since the objects have not finished processing yet. I am using Apache Camel 2.6 and Spring Remoting, and the Camel Aggregator would be ideal, except that each app server must have a duplicate camel context, so they would be competing for the aggregate components.
Perhaps a temporary queue and endpoint for each aggregation, but I'm not sure how to go about doing that, especially the tear-down. What would be the best way to process both objects, then deliver the container?
You could send a message to a topic when each object is finished. The message should contain the context id and the object id. Then you would have a from route on the topic. When a message is received it would persist the state in a simple db table and check if the other confirmation is already persisted. If yes it would deliver the container.
Related
I have REST API gateway which calls one of the microservices with MassTransit request client. This request is not durable and is meant to live for a short time - essentially it's just replacement of "traditional" synchronous (via HTTP/GRPC/etc) gateway-microservice communication.
On microservice side I have consumer which under the hood uses DbContext and Transaction (EFC) to perform some work in database. After the work is done it should publish "WorkDoneEvent" (to be consumed later by other microservices) and return result of the work to api gateway. Event must be published atomically along with transaction used to perform the work. It does not matter if ApiGateway will receive response / will retry request - as soon as transaction is commited both work result and sending "WorkDoneEvent" must be guaranteed.
Normally this is done with transactional outbox which first saves published event to database within same transaction as the work is done. (And then some process constantly "polls" outbox and tries send message to the broker, when done it removes message from outbox). As far as I know.
MassTransit seems to have transactional outbox built in: https://masstransit-project.com/advanced/middleware/transactions.html#transactional-bus.
However in docs it clearly states:
Never use the TransactionalBus or TransactionalEnlistmentBus when writing consumers. These tools are very specific and should be used only in the scenarios described.
And this is exactly what I want to do...
Why I should not do it?
I'd suggest using the InMemoryOutbox, which is part of MassTransit. It's significantly lighter weight, is designed to work in a consumer, and will not publish your events until after the consumer has completed (but prior to acknowledging the message at the broker). The only consideration is that your consumer should be idempotent (which needs to be the case in your approach as well) and if the operation was already performed on a retry, it should republish the events.
There are videos, articles, and a sample to go along with it.
I am facing an issue when decoupling two systems by an event/message broker like Apache Kafka. The issue is related to a frontend triggering actions in a backend:
How does the producer (frontend service) know, that the published event has been properly handled by all the backend services (as consumers), if the publisher does not know neither the "identities" nor the count of consuming backends?
To be precise: Users can change for example their email address using a frontend UI. An associated service publishes that "change request" event to an appropriate topic within Kafka. The UI form is then "locked" to prevent subsequent change requests, until the change event has been fully processed by every consumer. But it's unclear how to detect this state.
You can use another topic to publish handled jobs. So your front-end publishes to one topic and your back-end publishes to another once it is done.
In Kafka terms, neither the producer nor consumer are considered backend - they're both clients connecting to a broker, which is generally considered to be the backend.
A producer will know that it has produced a message successfully, by virtue of the acks setting. A consumer will read a message, and then at a later point, its offset will be updated to a point corresponding to the last message it read. However, there is generally no interaction between a producer and a consumer, and they are generally completely unaware of one another.
I am looking for a way for each consumer instance to receive a message that is published to RabbitMQ via MassTransit. The scenario would be, we have multiple microservices that need to invalidate a cache on notification. Pub-Sub won't work in this instance as there will be 5 consumers of the same type as its the same code per service instance, so only one would receive the message in a traditional PubSub.
Message observation could be an option but this means the messages would never be consumed and hang around forever on the bus.
Can anyone suggest a pattern to use in the context of MassTransit?
Thanks in advance.
You should create a management endpoint in each service, which could even be a temporary queue (just request a receive endpoint without a queue name and one will be dynamically generated). Then, put your queue invalidation consumers on that endpoint. Each service instance will receive a unique instance of the message (when Publish is called), and those queues and bindings will automatically be removed once the service exits.
This is exactly how the bus endpoint works, but in your case, you're creating a receive endpoint which can have consumer message type bindings, so that published messages are received, one copy per service.
cfg.ReceiveEndpoint(cfg => { ... });
Note that the queue name is not specified, and will be automatically generated uniquely.
Let's say, I have several micro-services (REST API), the problem is, if one service is not accessible (let's call service "A" ) the data which was sending to service "A" will be saved in temporary database. And after service worked, the data will be sent again.
Question:
1. Should I create the service which pings to service "A" in every 10 seconds to know service works or not? Or is it possible to do it by task queue? Any suggestions?
Polling is a waste of bandwidth. You want to use a transactional queue.
Throw all your outbound messages in the queue, and have some other process to handle the messages.
How this will work is - after your process reads from the queue, and tries to send to the REST service:
If it works, commit the transaction (for the queue)
If it doesn't work, don't commit. Start a delay (minutes, seconds - you know best) until you read from the queue again.
You can use Circuit Breaker pattern for e.g. hystrix circuit breaker from netflix.
It is possible to open circuit-breaker base on a timeout or when service call fails or inaccessible.
There are multiple dimensions to your question. First you want to consider using an infrastructure that provides resilience and self healing. Meaning you want to deploy a cluster of containers, all containing your Service A. Now you use a load balancer or API gateway in front of your service to distribute calls/load. It will also periodically check for the health of your service. When it detects a container does not respond correctly it can kill the container and start another one. This can be provided by a container infrastructure such as kubernetes / docker swarm etc.
Now this does not protect you from losing any requests. In the event that a container malfunctions there will still be a short time between the failure and the next health check where requests may not be served. In many applications this is acceptable and the client side will just re-request and hit another (healthy container). If your application requires absolutely not losing requests you will have to cache the request in for example an API gateway and make sure it is kept until a Service has completed it (also called Circuit Breaker). An example technology would be Netflix Zuul with Hystrix. Using such a Gatekeeper with built in fault tolerance can increase the resiliency even further. As a side note - Using an API gateway can also solve issues with central authentication/authorization, routing and monitoring.
Another approach to add resilience / decouple is to use a fast streaming / message queue, such as Apache Kafka, for recording all incoming messages and have a message processor process them whenever ready. The trick then is to only mark the messages as processed when your request was served fully. This can also help in scenarios where faults can occur due to large number of requests that cannot be handled in real time by the Service (Asynchronous Decoupling with Cache).
Service "A" should fire a "ready" event when it becomes available. Just listen to that and resend your request.
I am looking to implement an synchronous request-reply pattern using JMS inside a Java EE container. The sequence would be something like this
Browser makes a request to web application for data. This is a blocking request (say on thread T1).
The web app needs to connect to a remote web service to fulfill the above request. So it forms a request and places it on a queue (with a reply-to queue also declared).
The remote service processes the requests and places the response on to the reply-to queue declared in step 2
The response is read from the reply-to Q in the web app and made available to the blocking thread T1 of step 1.
I have followed the answer provided by T.Rob (How to match MQ Server reply messages to the correct request)
QueueReceiver queueReceiver =
session.createReceiver(destination, "JMSCorrelationID='customMessageId'");
TextMessage receivedMessage = (TextMessage)queueReceiver.receive( 15000 );
Is the above solution valid when running in a Java EE container (web module) where there could be multiple concurrent requests coming in?
This depends on the perception of "valid": It will probably compile and work. But from the design perspective, one could say that you can really improve it.
If your thread is blocking, any asynchronous communication won't add any value. Instead it will make it slow, it will consume resources, and it might even create trouble (see link below).
Whatever service is exposed by the the system processing the messages (possibly an MDB), extract it into a separate service class, and provide another frontend in the shape of a stateless session bean. So your service is exposed both by an sync and async interface, and the client can choose.
In your scenario your servlet just calls an EJB synchronously.
As for the problems which may happen otherwise: Have a look at JMS request/response pattern in transactional environment (this approach uses a temporary queue).
Using a single queue (the way you have quoted in your question), you need a selector (the condition) to get relevant messages: This might be slow, depending on the volume in the queue.
On the other hand, if you implement your servlet with asynchronous support as well (using #WebServlet(asyncSupported = true)), it's something different. In that case I would say it's a valid approach.
In that scenario you can save resources (namely threads; but the HTTP connections remain open), because one background thread listening on a queue can serve multiple clients. Consider this if you have performance or resource problems. Until then I suggest the synchronous way, because it is easier to implement.
The JMS Request/Reply of the EAI Patterns might fit for you.
It's well explained and there's also samples in Java:
http://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReplyJmsExample.html