Messages

A message is a distinct piece of information transmitted by one client that can be received by one or more other clients. Each SQS message is identified by an ID value generated by the service. A message’s ID uniquely identifies that message within a queue, and the combination of a queue URL and a message ID can uniquely identify any message in SQS.

There is no limit to the number of messages that can be sent to SQS queues, nor to the number that may remain stored in queues pending delivery. Messages cannot be left in the service indefinitely; they will be automatically deleted after 15 days or so.

Warning

SQS does not include a timestamp with messages to indicate when a particular message was sent. This makes it difficult to check whether your queues contain messages that are nearly 15 days old. SQS is not intended for long-term data storage, so you must be prepared for very old messages to be deleted.

Messages have a maximum size of 256 KB. This size limit is not large by the standards of alternative messaging systems, and it clearly indicates Amazon’s intentions for how its messaging service should be used. SQS is not intended to serve as a means for distributing files or transmitting large data objects; it is intended to carry short notifications or instruction messages that refer to data resources stored outside the SQS service, for example, in the Simple Storage Service (S3).

The data content of SQS messages must be unicode text characters that are legal for standard XML documents, as defined in the XML 1.0 character specification.[3] Legal unicode characters include those in the following ranges:

#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

If you need to transmit binary information, or you are in doubt about whether your messages will conform to these character set limitations, you should encode your message data using Base 64.

The SendMessage operation creates a new message in an SQS queue and makes it available for retrieval. Table 8-5 shows the SendMessage request parameters.

The SQS Query API allows messages to be sent using either HTTP GET or POST requests. The size limits for messages sent using GET is only 8 KB due to the fact that the entire message text must be included in the request’s URI, and URIs cannot become too long. POST requests store the message body along with the other parameters in the request’s body and therefore do not suffer from the same message size limitation.

Here is an XML document returned by the operation, including the message’s unique identifier value in the MessageId element.

<SendMessageResponse xmlns='http://queue.amazonaws.com/doc/2007-05-01/'>
  <MessageId>0WQR23VAFKFCYM4ZC9MM|72AD0F0NE09VCMT3AJ61|M57DGQ7TB0T3MFY3J1X0</MessageId>
  <ResponseStatus>
    <StatusCode>Success</StatusCode>
    <RequestId>06ea96d8-008a-41e7-8bb9-f3b6da5d6a65</RequestId>
  </ResponseStatus>
</SendMessageResponse>

Example 8-5 defines a method that sends a message to an SQS queue and returns the identifier of the newly created message. The message data can optionally be Base-64 encoded prior to being sent if the method parameter encode is set to true.

Here we demonstrate the vital difference between sending a message to a queue using a GET versus a POST request. We have included some of the debug logging information to highlight the difference in the URI between the two requests. Notice that the GET request requires a long URI even when the message is small, while the URI for the POST request is always quite short.

# Send a message using a GET request
irb> SQS::HTTP_METHOD = 'GET'
irb> sqs.send_message(queue_url, 'Hello SQS!')
REQUEST
=======
Method: GET
URI: http://queue.amazonaws.com/A1MU5FWLQSN7CU/testing?Action=SendMessage
     &Signature=kT3RopxqdtNrv6Tk1yOS4lcK3g0%3D
     &MessageBody=Hello+SQS%21
     &Version=2007-05-01
     &AWSAccessKeyId=ABCDEFGHIJ1234567890
     &Timestamp=2007-08-29T03%3A11%3A53Z
     &SignatureVersion=1
. . .
=> "0WQR23VAFKFCYM4ZC9MM|72AD0F0NE09VCMT3AJ61|M57DGQ7TB0T3MFY3J1X0"

irb> SQS::HTTP_METHOD = 'POST'
irb> sqs.send_message(queue_url, 'Hello SQS!')
REQUEST
=======
Method: POST
URI: http://queue.amazonaws.com/A1MU5FWLQSN7CU/testing
. . .
=> "1S5HB19QG48H4V6JYSEE|1SE7TJVAQZBXRPC11VS0|1SH8K2VEBJ99XCYY2JH0"

The ReceiveMessage operation allows an SQS client to receive messages that have been sent to a specific queue. This operation is slightly misnamed in the API, because it can actually receive more than one message at a time. The response for this operation includes a listing of messages with the ID and content data for each message.

Receiving a message from a queue does not delete the message from that queue. The receive action triggers the message to become invisible to subsequent ReceiveMessage requests for a period of time; this is called the message’s visibility timeout. The timeout to apply to received messages can be set with a parameter in the ReceiveMessage operation, or if no explicit timeout value is provided, the message is assigned the queue’s default visibility timeout. For more information on the visibility timeout and life cycle of messages, refer back to The Message Life Cycle.”

The ReceiveMessage operation allows you to specify a maximum limit for the number of messages you wish to receive; however, there is no guarantee that SQS will provide the number of messages requested, even if the queue contains more than enough messages. As we discussed in SQS Architecture,” SQS only checks a subset of its distributed servers for available messages. This means that any one receive request may return fewer messages than are actually available, and that multiple ReceiveMessage operations may be necessary to receive all of the available messages.

Here is an XML document returned by the operation, which includes a Message element for each message received from the service. The Message element includes two subelements: MessageId, which contains the message’s unique identifier, and MessageBody, which contains the message’s data content.

<ReceiveMessageResponse xmlns='http://queue.amazonaws.com/doc/2007-05-01/'>
  <Message>
    <MessageId>0NMA4SD7PN4TN0MF9ZZS|...|260BDAS2K7RNYSSR6GY1</MessageId>
    <MessageBody>Hello SQS!</MessageBody>
  </Message>
  <ResponseStatus>
    <StatusCode>Success</StatusCode>
    <RequestId>413154fa-18da-4002-81fe-3df6dbee0cf8</RequestId>
  </ResponseStatus>
</ReceiveMessageResponse>

Example 8-6 defines a method that receives messages from a queue and returns them as an array of hash dictionary objects. Each message is represented by a hash containing named mappings to the message ID and body content text. If the visibility_timeout parameter is provided with a duration value, the received messages will be made invisible to subsequent requests for the specified period of time.

To receive the messages we sent earlier, we will run the receive_messages method and store the results in the variable msgs, so we can have a closer look at them. In our examples we have sent two messages, so we will try receiving up to two messages in this request.

irb> msgs = sqs.receive_messages(queue_url, 2)
=> [{:body=>"Hello SQS!", 
    :id=>"0NMA4SD7PN4TN0MF9ZZS|1SE7TJVAQZBXRPC11VS0|260BDAS2K7RNYSSR6GY1"}]

irb> msgs.length
=> 1

Notice that our receive request returned only one message, not two as we might have expected. This is because one of our messages is stored on SQS servers that were not sampled during the operation. If we run the command a number of times, we will eventually receive all the available messages, although before long we will also start receiving redelivered messages because the visibility timeout for the original message will expire.

The DeleteMessage operation outlined in Table 8-7 removes a specific message from a queue. The message is deleted immediately, regardless of its visibility state or whether it has been delivered to any SQS clients.

You should delete messages from SQS as soon as possible once a message has reached the end of its useful life; messages will persist and may be redelivered if you do not remove them from the service.

Here is an XML document returned by the operation. The response contains no useful information beyond the status code.

<DeleteMessageResponse xmlns='http://queue.amazonaws.com/doc/2007-05-01/'>
  <ResponseStatus>
    <StatusCode>Success</StatusCode>
    <RequestId>7e53e4f7-07f3-40ca-8d7b-f4adda882289</RequestId>
  </ResponseStatus>
</DeleteMessageResponse>

Example 8-7 defines a method that deletes a specific message from a queue. The method returns true if the request succeeds.

We can test the new method by sending a new message and storing the message’s ID in the variable msg_id. Once we have this ID, we can delete the message. We can even delete the message multiple times; the delete operation will always succeed even though the message is only actually deleted the first time.

irb> msg_id = sqs.send_message(queue_url, 'Doomed message')
=> "1QJNM0VK5203GVAS2KP7|A617CAQHX0CS7N69WY71|RW2145BC0M6GHC5ZPAC1"

irb> sqs.delete_message(queue_url, msg_id)
=> true

irb> sqs.delete_message(queue_url, msg_id)
=> true

The PeekMessage operation described in Table 8-8 makes it possible to retrieve the data content of a message regardless of its visibility state, provided you know the message’s identifier. Unlike the ReceiveMessage operation, you can use the PeekMessage operation to view a message’s contents while the message is invisible, and peeking at a message does not trigger the message to become invisible.

You can only perform this operation when you know the message’s identifier in advance. For this reason, the PeekMessage action cannot be used as a replacement for the ReceiveMessage action. For a message receiver client to be able to peek at a message, it must first learn its identifier value, which it can do only by receiving the message.

The PeekMessage operation is most useful for tracking the progress of messages. For example, a message-sending client that knows the message’s identifier could determine whether or not a message has been processed by peeking at the message on the queue to see if it has been deleted.

Here is an XML document returned by the operation. The document includes a single Message element representing the peeked message. The Message element includes two subelements: MessageId, which contains the message’s unique identifier, and MessageBody, which contains the message’s data content.

<PeekMessageResponse xmlns='http://queue.amazonaws.com/doc/2007-05-01/'>
  <Message>
    <MessageId>1ZBAAYNJ59Y3ACC1SKWD|...|M57DGQ7TB0T3MFY3J1X0</MessageId>
    <MessageBody>Hello SQS!</MessageBody>
  </Message>
  <ResponseStatus>
    <StatusCode>Success</StatusCode>
    <RequestId>288526a0-fa04-4d2c-bbe2-2541c36bf702</RequestId>
  </ResponseStatus>
</PeekMessageResponse>

Example 8-8 defines a method that peeks at a message and returns its data content and identifier. It is fairly pointless to return the message’s identifier, because you must already know this value to perform the operation; however, this result structure will be consistent with the data structure returned by the receive_messages method.

To demonstrate message peeking, we will obtain message identifiers for the messages we sent previously and compare what happens when we peek at a message versus receiving it.

# Find a message identifier
irb> msg_id = sqs.receive_messages(queue_url).first[:id]
=> "1ZBAAYNJ59Y3ACC1SKWD|A617CAQHX0CS7N69WY71|M57DGQ7TB0T3MFY3J1X0"

# Peek at the message to retrieve its identifier and contents
irb> sqs.peek_message(queue_url, msg_id)
=> {:body=>"Hello SQS!", 
    :id=>"1ZBAAYNJ59Y3ACC1SKWD|A617CAQHX0CS7N69WY71|M57DGQ7TB0T3MFY3J1X0"}

To see where the peek operation can be very handy, we can try running the receive_messages method a few times, until we no longer receive any results; at this point all of our messages have become invisible to ReceiveMessage operations. Although we cannot receive these messages, we can still use a PeekMessage operation to view the message contents.

irb> sqs.receive_messages(queue_url, 10).length
=> 1
irb> sqs.receive_messages(queue_url, 10).length
=> 1
irb> sqs.receive_messages(queue_url, 10).length
=> 0

# All messages are invisible, yet we can still peek at the contents
irb> sqs.peek_message(queue_url, msg_id)
=> {:body=>"Hello SQS!", 
    :id=>"1ZBAAYNJ59Y3ACC1SKWD|A617CAQHX0CS7N69WY71|M57DGQ7TB0T3MFY3J1X0"}

We can determine when a message has been removed from a queue by checking for a 404 Not Found error response when we peek at the message.

irb> sqs.delete_message(queue_url, msg_id)
=> true

irb> sqs.peek_message(queue_url, msg_id)
AWS::ServiceError: HTTP Error: 404 - Not Found, AWS Error:
MessageNotFound - No such message with requested id

The ChangeMessageVisibility operation detailed in Table 8-9 modifies the visibility timeout duration for a specific message. A message’s visibility timeout can be adjusted at any time, regardless of the message’s prior visibility status.

Note

Alterations to the message’s timeout value take effect immediately, but they are one-off adjustments that apply only until the next visibility state change.

This operation can be used in a range of scenarios:

Here is an XML document returned by the operation. The response contains no useful information beyond the status code.

<ChangeMessageVisibilityResponse xmlns='http://queue.amazonaws.com/doc/2007-05-01/'>
  <ResponseStatus>
    <StatusCode>Success</StatusCode>
    <RequestId>104a8898-77db-4808-bd95-cd7728093f89</RequestId>
  </ResponseStatus>
</ChangeMessageVisibilityResponse>

Example 8-9 defines a method that changes a message’s visibility timeout setting and returns true provided the request was successful. If no value is provided for the visibility_timeout parameter, the message’s visibility timeout is set to 0 seconds, making the message visible immediately.

The best way to demonstrate this method is to call the receive_messages method repeatedly, until all our messages are in the invisible state. We will then reset the visibility timeout of one message to 0 seconds, making it visible immediately, and confirm that we can receive that message that has been made visible.

# Locate a specific message ID
irb> msg_id = sqs.receive_messages(queue_url).first[:id]
=> "0MXR9SQQT1JHFPK37JCN|72AD0F0NE09VCMT3AJ61|K6KT2VSF12BR9S52HCC0"

# Send receive requests until all your messages are invisible
irb> sqs.receive_messages(queue_url, 10).length
=> 1
irb> sqs.receive_messages(queue_url, 10).length
=> 0

# Reset the visibility timeout for one message
irb> sqs.change_message_visibility(queue_url, msg_id, 0)
=> true

# Confirm that you can now receive that message
irb> sqs.receive_messages(queue_url, 10)
=> [
{:body=>"Hello SQS!", 
 :id=>"0MXR9SQQT1JHFPK37JCN|72AD0F0NE09VCMT3AJ61|K6KT2VSF12BR9S52HCC0"}]


[3] See the character set section in Extensible Markup Language (XML) 1.0 (Fourth Edition) - http://www.w3.org/TR/REC-xml/#charsets