1
votes

Setting up a CMS consumer with a listener involves two separate calls: first, acquiring a consumer:

 cms::MessageConsumer* cms::Session::createConsumer( const cms::Destination* );

and then, setting a listener on the consumer:

void cms::MessageConsumer::setMessageListener( cms::MessageListener* );

Could messages be lost if the implementation subscribes to the destination (and receives messages from the broker/router) before the listener is activated? Or are such messages queued internally and delivered to the listener upon activation?

Why isn't there an API call to create the consumer with a listener as a construction argument? (Is it because the JMS spec doesn't have it?)

(Addendum: this is probably a flaw in the API itself. A more logical order would be to instantiate a consumer from a session, and have a cms::Consumer::subscribe( cms::Destination*, cms::MessageListener* ) method in the API.)

1
The SimpleAsyncConsumer example in the activemq-cpp distro is an utter horror show, a classic of bad wannabe C++. It looks like the work of a Java programmer trying to write C++.arayq2
If ActiveMQ CMS doesn't fulfill your needs there's always C++ clients which speak AMQP. Also, C++ STOMP clients. ActiveMQ supports both of these protocols.Justin Bertram
The less said about the Qpid Proton C++ client, the better. (The code base looks sounder, but the API, based on some goofy "proactor" design pattern, is from Mars; and AMQP 1.0 seems not well suited to pub/sub) I'm still getting useful mileage from CMS, though. Maybe the rough edges aren't insurmountable.arayq2
I'm also not averse to hacking the source code if needed. There are some pretty obvious howlers, e.g. the developers forgot - or didn't know - that C++ supports covariant return types, so you find Java-isms like ActiveMQConnectionFactory::createConnection() returning a cms::Connection*, gratuitously losing the subclass type that then would need a dynamic_cast to recover in client code... sigharayq2
It is open-source. I'm sure contributions would be welcome. Also, I believe that a new Qpid C++ client is being developed. See qpid.2158936.n2.nabble.com/… for discussion.Justin Bertram

1 Answers

0
votes

I don't think the API is flawed necessarily. Obviously it could have been designed a different way, but I believe the solution to your alleged problem comes from the start method on the Connection object (inherited via Startable). The documentation for Connection states:

A CMS client typically creates a connection, one or more sessions, and a number of message producers and consumers. When a connection is created, it is in stopped mode. That means that no messages are being delivered.

It is typical to leave the connection in stopped mode until setup is complete (that is, until all message consumers have been created). At that point, the client calls the connection's start method, and messages begin arriving at the connection's consumers. This setup convention minimizes any client confusion that may result from asynchronous message delivery while the client is still in the process of setting itself up.

A connection can be started immediately, and the setup can be done afterwards. Clients that do this must be prepared to handle asynchronous message delivery while they are still in the process of setting up.

This is the same pattern that JMS follows.

In any case I don't think there's any risk of message loss regardless of when you invoke start(). If the consumer is using an auto-acknowledge mode then messages should only be automatically acknowledged once they are delivered synchronously via one of the receive methods or asynchronously through the listener's onMessage. To do otherwise would be a bug in my estimation. I've worked with JMS for the last 10 years on various implementations and I've never seen any kind of condition where messages were lost related to this.

If you want to add consumers after you've already invoked start() you could certainly call stop() first, but I don't see any problem with simply adding them on the fly.