Message Driven Beans - Single Bus, Multiple Activation Specs - java

I have 2 Message driven beans. 2 Activation Specs for these beans. I have one Message bus and both the activation specs are configured to this one bus. I have 2 different queues and one queue connection factory configured for that one Message bus.
Now, I would write my code to send a message to one of the queues at runtime after determining the queue. However, both my MDBs receive the same message.
How is this configuration done in general? Do I always configure 1 Queue -> 1 Queue Connection Factory -> 1 Message Bus -> 1 MDB? Is it all a one-to-one relationship?
Oh, I forgot to mention this: I am using Websphere Application Server v6.1

In general the concept is that:
a message is sent(Queue)/published(Topic) to a destination (Queue/Topic)
the ActivationSpec listens to messages at a particular destintation (Queue/Topic)
ActivationSpec : Destination is a 1:1 relationship
A bean (MDB which is a consumer) is configured to listen to an ActivationSpec.
What this means is that in effect the bean is linked to a destination with a layer of indirection provided by the activationSpec.
Where does the bus come in - SIBus is the messaging infrastructure that makes all this possible. Destinations are hosted on the bus.
Coming to the question - the ActivationSpec would be configured to listen to a destination on the bus to which messages would be sent. The connection factory decides the bus to which message would be sent. As long as the destination name is unique and targetted to a specific queue (JMS Queue is linked to destination on the bus) one message would only be received by one ActivationSpec.
how many destinations (under SIBus link in WAS admin console) have been created on the bus ? Could you check/validate if the configuration is correct?
to answer your questions - "Is it one bus per activation spec and one queue connection factory per queue." - the answer is NO.
Bus is the underlying infrastructure that can host "n" destinations. One ActivationSpec listens to one destination.
With queue connection factory is a factory (J2EE factory pattern) for creating queues.

I think you're saying you want both MDBs to receive the same message, right?
If this is the case then the MDBs should be listening to a topic not a queue.
Alternatively, there are ways you can configure IBM MQ to forward messages, so for example a message posted to a particular queue could be re-posted to n other queues, but I've only seen that used when some sort of message enrichment takes place before the re-posting and so I suspect would be overkill for what you're trying to achieve.

Why do you need the message bus?
Usually I associate an MDB with a queue - it's a 1:1 relationship. Send a message to a queue, the listener gets it. What is the bus buying you?
I've done JMS with WebLogic, and there's no such construct as a message bus required. I think it's an IBM thing.
Here's an example of how to do JMS with Spring. That's how I'd recommend proceeding.
UPDATE: I misinterpreted your question. When you said both your queues were getting the same message, I didn't think that was the desired behavior. If it is, then topics are the correct way to go. Queues are point-to-point messaging; topics are publish/subscribe.

I suspect the configuration you have is not set up the way you think it is. We use the same configuration your described, with many MDB's (with a queue and activation spec), a single factory and message bus and everything works as expected.
To get the behaviour you are seeing is not actually possible unless you either send the same message to both queues, or have defined a topic instead of a queue. I am pretty sure that even if both MDB's are reading from the same queue, only one will get the message, since a queue only supports point to point messaging. What you have described is topic based behaviour.

Related

Two way RMI with Spring backed by a message queue

The system consists of 1 or more clients and a single server. Each client is added manually and provided with an identifier (client.id). Each client can send messages to the server. The server can send messages to each client. All messages can be divided into two groups: with an answer and without.
For example some signatures:
CompletableFuture<Response> call(Request requestToServer)
void execute(Data dataToSend)
where Response, Request, and Data are my POJO.
So, I need some sort of RMI for implementing message communication between the server and clients.
Requirements:
The server must be able to identify a client by its id client.id when processing a message, but the client, before sending that message, should not directly fill this identifier;
Messages should be POJO;
Ability to answer to a message with an exception;
Event-driven handlers (like #RabbitListener) - several handlers - spring bean per incoming message type, with or without return type. A handler should be resolved automatically, based on incoming message type;
Backed by RabbitMQ or ArtemisMQ;
Single service for sending messages from the server to clients: client id should be provided when sending a message. Example: void sendToClient(int clientId, Data dataToClient).
What I've tried to set up this method of communication:
Spring Integration
My own gateway with completable future - great. Also, can enrich message headers with client.id - great. But I didn't find an appropriate way to handle an incoming message and being able to answer it. Tried to publish an ApplicationEvent, but all event handlers have a void return type. So, my idea here is to get correlationId and send back message, providing that correlationId - that doesn't look like a clear solution.
RabbitListener/RabbitTemplate
Cons:
A lot of code to setup RabbitTemplate to send and receive messages;
Need to manually setup request and reply queues and bindings;
problem with resolving client.id inside #RabbitHandler.
AmqpProxyFactoryBean
The closest result to my needs, but several problems, that I cannot solve:
Resolve client.id on message handler;
Single handler per service interface method.
So, I need a lightweight solution to build up communication between services, backed by a message queue. It should be easy to add additional message type - declare the class, add the handler to the consumer and create an object of that class and send it from the producer.
But maybe I'm completely wrong, about services communication? Maybe I should not use message queue for that purpose?
Well using a message queue or message broker like RabbitMQ is a perfectly valid solution. But you have to think whether it is what you actually need.
A message broker allows you to decouple the producers and consumers of messages. It also allows you to introduce a level of fault tolerance. If the consumer is not available temporarily the message is not lost. However, it also means that if a reply is expected the producer of the message might incorrectly think that the other end has processed its request and keep waiting for a reply. Message brokers also often offer some kind of guarantee, like once-and-only-once, or at-least-once, and also policies how to handle undeliverable messages (like dead letter queues), time-to-live, and various routing capabilities (like consistent hash based routing). In your case, you will probably have to route by some header value carrying your client.id if your server-originated messages are to reach one client only.
If you don't care about any of these features and just want a communications fabric, maybe going for something a bit different might make more sense. For example Akka offers actor-based distributed communication.
If what is bothering you is just the cleanliness of the solution, or the amount of boilerplate, maybe having a look at other implementations might help. You might want to have a look at the Reactive Streams API implementation for RabbitMQ, which should be a bit more abstract.

Message Groups in WebSphere MQ

I have a requirement that I need to process JMS Messages (via MDB) in a way that Messages belonging to a certain group (a group ID is set) are consumed by the same bean instance. The behaviour I require in this is that Messages with the same group ID are processed sequentially (though message ordering is irrelevant), and tying them to the same MDB-instance should provide that.
The messages do not carry any kind of sequence number (as it is irrelevant) and we do not know what the first or last message in a group is (there could theoratically "never" be a last message in a group). We want them to be delivered as soon as the consumer is able to receive them.
ActiveMQ provides this exact feature (http://activemq.apache.org/message-groups.html) by simply setting JMSXGroupID. We are bound to WebSphere MQ, though. All I've found out so far is that it is possible to collect Messages of the same group in the queue and using a MessageSelector to receive a "Last Message in Group" Message as described in http://www.ibm.com/developerworks/websphere/library/techarticles/0602_currie/0602_currie.html. We would prefer a cleaner way though (like in ActiveMQ). Does anyone know how to achieve that behaviour in WebSphere?
Thanks!
Generally you use MessageSelectors in IBM product implementations of JMS (both WebSphere MQ and SIBus implementations). These are the equivalent of a filter that would scan the header of an HTTP or SOAP message for web-based protocols.
Though it may not be what you want, it actually is a clean and well thought through design.
However, if you do not want to use MessageSelectors, you will probably have to build your own and "process" a message with a fronting MDB that scans the headers, and then forwards the message to an appropriate queue, where only the MDB that cares about the grouped messages will process them (sort of a gateway/message selector pattern).
If you are using the "pure" JMS API's, then you can ask the Session object to create a MessageConsumer with the specified selector string (value in the header) you want to filter on (again you have to set this yourself).
//assume we have created a JMS Connection and Session object already.
//and looked up the Queue we want already.
MessageConsumer consumerWithSelector = session.createConsumer(queue, groupId);
This is all the pure JMS API's give you. Anything else is purely up to the implementer of the messaging technology, which is then proprietary to their implementation and not portable code.

ActiveMQ: How to handle broker failovers while using temporary queues

On my JMS applications we use temporary queues on Producers to be able to receive replies back from Consumer applications.
I am facing exactly same issue on my end as mentioned in this thread: http://activemq.2283324.n4.nabble.com/jira-Created-AMQ-3336-Temporary-Destination-errors-on-H-A-failover-in-broker-network-with-Failover-tt-td3551034.html#a3612738
Whenever I restarted an arbitrary broker in my network, I was getting many errors like this in my Consumer application log while trying to send reply to a temporary queue:
javax.jms.InvalidDestinationException:
Cannot publish to a deleted Destination: temp-queue://ID:...
Then I saw Gary's response there suggesting to use
jms.watchTopicAdvisories=false
as a url param on the client brokerURL. I promptly changed my client broker URLs with this additional parameter. However now I am seeing errors like this when I restart my brokers in network for this failover testing:
javax.jms.JMSException:
The destination temp-queue:
//ID:client.host-65070-1308610734958-2:1:1 does not exist.
I am using ActiveMQ 5.5 version. And my client broker URL looks like this:
failover:(tcp://amq-host1:61616,tcp://amq-host2.tred.aol.com:61616,tcp://amq-host3:61616,tcp://amq-host4:61616)?jms.useAsyncSend=true&timeout=5000&jms.watchTopicAdvisories=false
Additionally here is my activemq config XML for one of the 4 brokers:
amq1.xml
Can someone here please look into this problem and suggest me what mistake I am making in this setup.
Update:
To clarify further on how I am doing request-response in my code:
I already use a per producer destination (i.e. temporary queue) and set this in reply-to header of every message.
I am already sending a per message unique correlation identifier in JMSCorrelationID header.
As far as I know even Camel and Spring are also using temporary queue for request-response mechanism. Only difference is that Spring JMS implementation creates and destroys temporary queue for every message whereas I create temporary queue for the lifetime of the producer. This temporary queue is destroyed when client (producer) app shutsdown or by the AMQ broker when it realizes there are no active producer attached with this temporary queue.
I am already setting a message expiry on each message on Producer side so that message is not held up in a queue for too long (60 sec).
There is a broker attribute, org.apache.activemq.broker.BrokerService#cacheTempDestinations that should help in the failover: case.
Set that to true in xml configuration, and a temp destination will not be removed immediately when a client disconnects.
A fast failover: reconnect will be able to producer and/or consume from the temp queue again.
There is a timer task based on timeBeforePurgeTempDestinations (default 5 seconds) that handles cache removal.
One caveat though, I don't see any tests in activemq-core that make use of that attribute so I can't give you any guarantee on this one.
Temporary queues are created on the broker to which the requestor (producer) in your request-reply scenario connects. They are created from a javax.jms.Session, so on that session disconnecting, either because of client disconnect or broker failure/failover, those queues are permanently gone. None of the other brokers will understand what is meant when one of your consumers attempts to reply to those queues; hence your exception.
This requires an architectural shift in mindset assuming that you want to deal with failover and persist all your messages. Here is a general way that you could attack the problem:
Your reply-to headers should refer to a queue specific to the requestor process: e.g. queue:response.<client id>. The client id might be a standard name if you have a limited number of clients, or a UUID if you have a large number of these.
The outbound message should set a correlation identifier (simply a sting that lets you associate a request with a response - requestors after all might make more than one request at the same time). This is set in the JMSCorrelationID header, and ought to be copied from the request to the response message.
The requestor needs to set up a listener on that queue that will return the message body to the requesting thread based on that correllation id. There is some multithreading code that needs to be written for this, as you'll need to manually manage something like a map of correlation ids to originating threads (via Futures perhaps).
This is a similar approach to that taken by Apache Camel for request-response over messaging.
One thing to be mindful of is that the queue will not go away when the client does, so you should set a time to live on the response message such that it gets deleted from the broker if it has not been consumed, otherwise you will get a backlog of unconsumed messages. You will also need to set up a dead letter queue strategy to automatically discard expired messages.

do message queues provide transactional support?

Say I load messages in a queue from multiple nodes.
Then, one or many nodes are pulling messages from the queue.
Is it possible (or is this normal usage?) that the queue guarantees to not hand out a message to more than one server/node?
And does that server/node have to tell the queue it has completed the operation and the queue and delete the message?
A message queuing system that did not guarantee to hand out a given message to just one recipient would not be worth the using. Some message queue systems have transactional controls. In that case, if a message is collected by one receiver as part of a transaction, but the receiver does not then commit the transaction (and the message queue can identify that the original recipient is no longer available), then it would be reissued. However, the message would not be made available to two processes concurrently.
What messaging/queuing technology are you using ? AMQP can certainly guarantee this behaviour (amongst many others, including pub/sub models)
If you want this in Java - then a JMS compliant messaging system will do what you want - and most messaging systems have a JMS client. You can Use Spring's JmsTemplate for real ease of use too.
With JMS - a message from a Queue will only be consumed by one and only one client - and once it is consumed (acknowledged) - it will be removed from the messaging system. Also when you publish a message using JMS - if its persistent - it will be sent synchronously, and the send() method won't return until the message is stored on the broker's disk - this is important - if you don't want to run the risk of loosing messages in the event of failure.

Need Help with Java JMS ResourceAllocationException

I am getting the following error:
javax.jms.ResourceAllocationException: [C4073]: A JMS destination limit was reached. Too many Subscribers/Receivers for Queue
The setup was done in such a way that there is one provider and two consumers.
Is the reason this error is happening because it is a queue and it can only have one provider and one consumer?
Queues in JMS are point-to-point mechanisms, you're not supposed to use them if you have multiple consumers. You should use topics for that.
Post the full code if you'd like, so we can try and help more, since it's not really clear what your code is doing.
JMS basic concepts
http://java.sun.com/products/jms/tutorial/1_3_1-fcs/doc/basics.html
That being said, according to Sun, this is the info for this error:
C4073
Message A JMS destination limit was reached. Too many Subscribers/Receivers for {0} : {1}
{0} is replaced with “Queue” or “Topic” {1} is replaced with the destination name.
Cause The client runtime was unable to create a message consumer for the specified domain and destination due to a broker resource constraint.
You actually can use queues with multiple consumers. Topics may not be what you want. A topic will work as a publish/subscribe model, where each consumer will get a copy of the message; whereas with queues, the JMS provider should only dispatch the message to one consumer.
There might be a config setting on your JMS provider that is limiting you to one consumer per queue. I've only used ActiveMQ for JMS, but it allows you to have mutliple consumers on a single queue - it basically load balances the requests between the consumers.

Categories