Simple Queue Service

Amazon Simple Queue Service provides a simple way to set up queues of messages that you can use for managing workflows or queuing up work to do. This PHP class is a convenient REST-based interface to that service.

A bit of example code will be a good demonstration of how simple this class is to use. Please read through these examples, and then feel free leave a comment if you have any questions or suggestions.

This document is based on version 1.0.0 of the SQS class, which is designed to use API version 2009-02-01. If you’ve been using 0.9.2, remember that 1.0.0 is not backward-compatible. You should still be able to use 1.0.0 to access queues you created with 0.9.2, since the AWS API versions they use are compatible, but I have not actually tested that. Also note that unlike 0.9.2, the new version cannot be used statically, and by default it uses SSL for createQueue and listQueues.

So, let’s get started. First, you’ll need to create an SQS object:

require_once('sqs.php');
$sqs = new SQS('Access Key Here', 'Secret Key Here');

If you don’t already have a queue, you’ll want to create one:

$response = $sqs->createQueue('testQueue');
$queue = $response['QueueUrl'];
print_r($response);
-------
Array
(
    [QueueUrl] => https://sqs.us-east-1.amazonaws.com/123456789012/testQueue
    [RequestId] => 7b20a1b9-30eb-412a-b3e9-62102eb0da28
)

Every request to SQS will include a request identifier in the response. If you need to contact AWS about problems with a particular request, you can provide a relevant request identifier to give them more information to work with.

createQueue also optionally accepts a second parameter which sets the queue’s default message visibility timeout, in seconds, if you want to override the default value.

Note that by default, this class uses SSL. At the end of this document I’ll explain how to override that behavior.

Alternatively, if you want to get the URL of an existing queue, you can list the queues on your account:

$response = $sqs->listQueues();
$queue = $respose['Queues'][0];
print_r($response);
-------
Array
(
    [RequestId] => 790fcea6-3df5-4a88-aef7-08964164239e
    [Queues] => Array
        (
            [0] => https://sqs.us-east-1.amazonaws.com/123456789012/testQueue
        )
)

The QueueUrl in the createQueue or listQueues response is the value you’ll need for all the rest of the calls. Note that this URL is not just the queue name you chose in the createQueue call; instead it is a composite value including the request method (HTTP or HTTPS), the SQS endpoint, your AWS account ID, and the queue name. You need to use this full value to interact with your queue.

Now that we have a queue, let’s send a message:

print_r($sqs->sendMessage($queue, 'This is a test message')));
-------
Array
(
    [RequestId] => 21d1ade3-8155-477d-89df-27f62ba1c28b
    [MD5OfMessageBody] => fafb00f5732ab283681e124bf8747ed1
    [MessageId] => 9f9acefd-01da-46db-adb5-40af35dfc7c6
)

If you want, you can use the MD5OfMessageBody element of the response to verify that your message was received correctly by SQS.

After waiting around 30 seconds, you should be able to retrieve the message you just posted:

$messages = $sqs->receiveMessage($queue);
print_r($message);
-------
Array
(
    [RequestId] => 0c8873fb-4cc9-448c-8ccf-c47386ada8ff
    [Messages] => Array
        (
            [0] => Array
                (
                    [MessageId] => 9f9acefd-01da-46db-adb5-40af35dfc7c6
                    [ReceiptHandle] => +eXJYhj5rDp/nuICOhmUlU2FDPkkD0EakC69z4M8ETl0DJ3gVOmjI2Gh/oFnb0IeJqy5Zc8kH4JARkzdFBpldzaAPSeOkXQZ613q3nEK3/fYDe0gheqkcx7CJOIiU743A19ENUGSgTpADQFIpn7IOgSCsMbsyUkKW+UUMXRDpAI=
                    [MD5OfBody] => fafb00f5732ab283681e124bf8747ed1
                    [Body] => This is a test message
                )
        )
)

By default, receiveMessage will retrieve up to ten messages from the queue. You can see here that the MessageId field matches what we got from the sendMessage call, as do the MD5OfBody and Body fields. Once you have a message, you’ll do whatever processing you need, and then you’ll want to delete the message from the queue.

However, you don’t use the MessageId to do that, you use the ReceiptHandle, like this:

$m = $messages['Messages'][0];
$sqs->deleteMessage($queue, $m['ReceiptHandle']);

deleteMessage will return a request id if you need it.

That’s all there is to it! There are, of course, several other things you can do with your queues. I’ll summarize them here, but I won’t provide sample output in the interest of brevity.

You can retrieve the attributes set on your queue, or a specific attribute if you know which one you’re interested in (see the GetQueueAttributes documentation for a list of possible attributes):

print_r($sqs->getQueueAttributes($queue));
print_r($sqs->getQueueAttributes($queue, 'ApproximateNumberOfMessages'));

You can set one or more attributes, as well (see the SetQueueAttributes documentation for a list of attributes you can set):

$attributes = array();
$attributes['VisibilityTimeout'] = 180;
$attributes['MaximumMessageSize'] = 65536;
// etc
$sqs->setQueueAttributes($queue, $attributes);

If you’ve received a message, but you’re not ready to delete it and you don’t want the message to become visible again in the queue, you can change the visibility for a specific message:

$sqs->changeMessageVisibility($queue, $message['ReceiptHandle'], $new_visibility_timeout);

You can share your queue with other AWS accounts, giving them access to specific operations. You pass in a unique label of your choice, and a list of permissions you want to associate with the label. The permissions array should be a mapping of AWS account ID (not access keys or secret keys!) to the permissions you want to grant:

$permissions = array();
$permissions['125074342641'] = 'SendMessage';
$permissions['125074342642'] = 'ReceiveMessage';
$sqs->addPermission($queue, 'AccessForJimAndSteve', $permissions);

Note that SQS will reject the request if any of the account IDs are invalid. See the documentation on Shared Queues for more information.

You can of course also remove previously-granted permissions:

$sqs->removePermission($queue, 'AccessForJimAndSteve');

If you no longer need a queue, you can delete it, even if there are still messages in the queue:

$sqs->deleteQueue($queue);

listQueues takes an optional prefix argument, so for example, this call will list all queues that begin with “sprocket”:

print_r($sqs->listQueues('sprocket'));

If you have three queues named sprocketSales, sprocketShipping, and widgetDistribution, then that call would only list the first two.

receiveMessage has three optional arguments in addition to the queue name:

$attributes = array('SentTimestamp', 'SenderId');
$messages = $sqs->receiveMessage($queue, $num_messages, $visibility_timeout, $attributes);

$num_messages can be any number between 1 and 10, and $visibility_timeout overrides the queue’s default visibility timeout for the $num_messages messages it retrieves. $attributes is a list of message attributes to retrieve in addition to the normal message data. See the ReceiveMessage documentation for more information.

Finally, the createQueue and listQueues calls use the endpoint that is set when the SQS object is created, which by default is the us-east-1 endpoint; you can choose a different endpoint if you want. For example, to interact with the us-west-1 endpoint by default, do this:

$sqs = new SQS('AccessKey', 'SecretKey', SQS::ENDPOINT_US_WEST);

The SQS class has some constants you can use instead of having to remember the endpoint URLs yourself:

  • SQS::ENDPOINT_US_EAST
  • SQS::ENDPOINT_US_WEST
  • SQS::ENDPOINT_EU_WEST
  • SQS::ENDPOINT_AP_SOUTHEAST

This class uses HTTPS by default; if you can’t or don’t want to use SSL, you can use these constants instead, which use HTTP rather than HTTPS:

  • SQS::INSECURE_ENDPOINT_US_EAST
  • SQS::INSECURE_ENDPOINT_US_WEST
  • SQS::INSECURE_ENDPOINT_EU_WEST
  • SQS::INSECURE_ENDPOINT_AP_SOUTHEAST

Note that regardless of what endpoint you specify in the constructor, the class will use whatever method and endpoint it finds in the $queue parameter of the various calls. If you have this setup:

$sqs = new SQS('AccessKey', 'SecretKey', SQS::ENDPOINT_EU_WEST);
$queue1 = 'https://sqs.us-east-1.amazonaws.com/123456789012/testQueue';
$queue2 = 'http://sqs.ap-southeast-1.amazonaws.com/123456789012/anotherQueue';
$sqs->getQueueAttributes($queue1);
$sqs->getQueueAttributes($queue2);

Both getQueueAttributes calls will do the “right” thing. The first call will connect via HTTPS to the us-east-1 endpoint, and the second will connect insecurely (without SSL) to the ap-southeast-1 endpoint. Neither call cares what the default endpoint was set to in the constructor. The default endpoint is only used if you call createQueue or listQueues.


Disclaimer: Although I work for Amazon (the RDS team, specifically), this class was neither produced, endorsed nor supported by Amazon.  I wrote this class as a personal project, just for fun.  While I no longer maintain it, I am happy to help resolve issues encountered while trying to use it.

13 Comments »

 
  • Eric says:

    Very nice indeed! And great explanations. Thanks for sharing.

  • nbari says:

    Is there a way to have a daemon listening to the queue so when a message arrive can quickly dispatch it ?

    • Dan says:

      You can use cron to run a PHP script at regular intervals to check the queue. If you want a true daemon that can do its own scheduling and polling and whatnot, you probably want to use something that’s not PHP, like C or Java, and it’s more work.

  • Robert says:

    Thanks!

    I just needed to post messages from PHP to an AWS queue, all other examples I found were bloated and too wordy.

    Your class and the examples above were exactly what I wanted. Got it up and working in under 5 minutes. Conciseness is a virtue!

  • David says:

    Thanks

    I was going crazy.

  • Tobias says:

    Hi,

    reviewing the code I found a possible typo in line 432. It says:

    $rest = new SQSRequest($this, $queue, ‘RemvoePermission’, ‘POST’);

    Shouldn’t this be “RemovePermission” instead?

    Tobias.

  • vincent says:

    Hello,

    Using your codes, i can easily manage SQS, thanks!
    But there is a question: At the end of May everything was fine but theresdays, when i use ‘receiveMessage’ there is a warmning:

    “SQS::receiveMessage(): Error SignatureDoesNotMatch caused by Sender.
    Message: The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.”

    But it’s functional when I use ‘createQueue’

    Could you give me some advice on it ?

    Many thanks

    • PR says:

      Hi Vincent

      I am also occasionally getting this error.
      Today 27 Sept 2013 the sendMessage stopped working and started throwing XML parsing errors.
      After many hours of working I found that the PUT HTTP command that was being used in the createeQueue and sendMessage is somehow not working any more. I replaced that with a GET and it is working.

      This is an excellent piece of work done by Dan and if we can keep it alive that will be good as the AWS libs require the latest version of PHP which is a pain.

  • will says:

    In the amazon documentation http://docs.aws.amazon.com/aws-sdk-php/guide/latest/service-sqs.html#sending-messages it talks about long polling but what would be the correct way to handle repeat long polls?
    I have had a look around and see an explanation of how to set it up at http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-long-polling.html , but this mostly talks about how to set it up on Amazon end as opposed to the actual implementation.

    I am unsure of what to do keep the PHP service active. A couple of possibilities would be

    A-have the long poll run for 20 seconds, close once finished receiving the messages and also have a cron job run every twenty seconds. This would mean that there would always be an active connection but with the maximum message count being 10 at a time and the cron job not running again for 20 seconds this limits the count of messages to 10 every 20 seconds or one every two seconds.

    B-alternatively we could run the long poll and as soon as the long poll completes fire off another one. This way if we get new messages at two seconds and then again at four and six seconds we would see all of those but if our function failed at any time it would miss everything.

    Of course we could use some combination of these two. One technique could be having a cron job running which looks to be see how recently B was active. If more than a certain time then we can start it up again.

    Interested to hear your feedback, I want to build a system which scales up efficiently. Thanks

    Will

    • KevinH says:

      Sorry if this is way late, but I just ran into something similar trying to get a python script to process some incoming sqs messages with decently low latency. The solution I settled on was to use upstart on an EC2 ubuntu instance. It handles logging, starting on boot and respawning processes in the event of an error. The stack-overflow article that put all the pieces together for me was here:

      http://stackoverflow.com/questions/17747605/daemon-vs-upstart-for-python-script

      I’m sure you could do somethign similar with php

  • Simon says:

    Good Morning,

    When I ask to list the Queues using $response = $sqs->listQueues();, it does list a blank queue.

    But when I ask to create a queue using this code:

    $response = $sqs->createQueue(‘testQueue’);
    $queue = $response[‘QueueUrl’];
    print_r($response);

    It create a queue here https://sqs.us-east-1.amazonaws.com/448381976349/testQueue

    When I go to SQS, it doesn’t show this queue.

    Because my SQS is https://console.aws.amazon.com/sqs/home?region=us-west-2. It doesn’t show the queue that I’ve created.

    But when I access https://console.aws.amazon.com/sqs/home?region=us-east-1#queue-browser:prefix=, I can see the queue.

    How can I set a parameter to create the queue using us-west-2?

    Regards,

  • Simon says:

    I did found out how to change the queue location changing some const in the SQS Class.

    I don’t know if there is still someone who moderate this website, but thanks for all the hard work.

    I was doing the course Lynda Up and Running with Amazon Web Services_2013 and there was a lot of errors in the code, this page did help me a lot to fix them and be able to run the examples to understand the code.

    Regards,

  • dasharath says:

    hi

    I got error while trying to implement this.
    can anyone help me how to resolve this error.
    Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied.

    thanks

 

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>