After years of using ActiveMQ 5.x in our Java-based production system, we decided to migrate to the Amazon Simple Queue Service (SQS). Managing and configuring ActiveMQ no longer seemed to make sense, especially when SQS does it for us. Moreover, SQS recently added FIFO support. Messages in SQS FIFO queues are delivered in order and are guaranteed to be processed only once. These features are exactly what we needed to replace ActiveMQ with SQS and ensure that our backend processes would function as expected.
Before migrating to SQS, here are some important considerations:
- JMS support is limited to queues, i.e., point-to-point.
- Message size is limited 256 KB.
- Message content is restricted to text only, i.e., XML, JSON, and unformatted text. JMS’s
StreamMessageinterfaces are unsupported.
- Message durability is constrained to a maximum of 14 days (defaults is 4 days).
- JMS selectors for filtering messages are unsupported.
My company Rodax Software provides a propriety RESTful API for Skedi—a calendar aggregation app for families and teams. The API has many long running tasks, so we use queues to manage the workflow while providing fast HTTP responses to our mobile clients.
Our messaging architecture includes queues that are consumed by server-side components and remote mobile clients. Since migrating the mobile clients to SQS would require code changes and an App Store update, we decided to first migrate the server queues.
Before diving into the code, we also had to consider SQS’s JMS compliance. Thankfully, SQS supports most of the JMS 1.1 specification for queues, click here for more information about using JMS with Amazon SQS.
Given the JMS queue support in SQS, the server-side code changes were relatively painless. So, lets take a look at them, which includes accessing a JMS connection, starting a JMS listener, sending a JMS message, and converting MapMessage to ObjectMessage.
Accessing a JMS connection
The primary difference between instantiating a JMS connection in SQS and ActiveMQ is that SQS requires credentials and the region where the queues are located.
Note: Using the
DefaultAWSCredentialsProviderChain class, which is the preferred method for accessing AWS credentials.
Starting a JMS Listener
Unlike ActiveMQ, a SQS JMS listener must be listening to a queue that actually exists; therefore, before we start listening, we ensure that the queue exists.
Lines 11-15 above were added because Amazon requires the queues to be created before first use. Lines 23-27 were to added to force the main thread to wait for one second after starting the listener. Lines 30-46 is a new method to create the FIFO before we start listening.
Sending a JMS Message
Sending a message to a FIFO queue requires only one additional line of code to set the message group ID.
For more information about these changes click here.
Converting MapMessage to ObjectMessage
SQS doesn’t support
MapMessage; therefore, we simply refactored by converting our
MapMessage objects to
HashMap<String, String> instances. Note: An
ObjectMessage object must implement
Voilà! The next thing we have to do is to migrate our mobile clients using the ActiveMQ Stomp protocol and JMS selectors. Replacing the selector filtering will most likely require architectural changes. In any case, once we’ve completed the mobile migration, I’ll blog about it here too.
To conclude, it’s worth noting that these SQS migration changes should work with any JMS compliant codebase. Let me know if you have any experiences or thoughts to share.