Cloud computing with PHP, Part 3: Using Amazon SQS with the Zend Framework

Using simple message queues with the Zend Framework

The Zend Framework contains several classes that make using cloud-based services easy. Part 1 of this "Cloud computing with PHP" series looks at using Zend classes with Amazon's S3 cloud storage service. Part 2 covers the Zend classes that make it easy to work with virtual machines in Amazon's Elastic Compute Cloud (EC2). This article focuses on the Zend classes for working with Amazon's Simple Queue Service (SQS).

Share:

Doug Tidwell (dtidwell@us.ibm.com), Cloud Computing Evangelist, EMC

Doug Tidwell is a senior software engineer in IBM's Emerging Technology group. He was a speaker at the first XML conference in 1997, and he has been working with markup languages, Web services and SOA (the technologies beneath the cloud) for many years. His presentations have been featured at dozens of conferences around the world, and his JavaOne presentation on cloud computing earned him a Rock Star award in 2009. His job as a technology evangelist is to explain the standards and technologies behind cloud computing and to help customers integrate them into their overall business architectures and strategies. He is the author of many developerWorks articles, and is the author of O'Reilly's book on XSLT, a copy of which makes a perfect gift for any occasion. He lives in Chapel Hill, N.C., with his wife, daughter, and dog.


developerWorks Contributing author
        level

30 March 2010

Also available in Russian Portuguese

Amazon's SQS provides the basic functions of a message queueing system. Although SQS is not designed to replace an enterprise-grade messaging system, it does have a variety of useful features. This article looks at the methods in the Zend Framework that make it easy to work with messages and queues in SQS.

Getting started

In this article, you'll see how to do several important tasks with the Simple Queue Service. As with all of the articles in this series, you'll get the most out of the examples if you have the Zend Framework installed before you begin. If you don't have it installed, download and install the full package from Zend.com (see Resources). This installs the Zend Framework, PHP, and the Apache Web server on your machine. When the install is complete, go to http://localhost/ZendServer/. See the Zend Framework installation documentation for the details. If you can log in to the ZendServer console, you're all set.

You'll also need to set up an account with Amazon (see Resources).

The examples use the PHP Credentials class created in Part 1. That class manages the credentials for your Amazon account. The credentials are stored in an .ini file:

Listing 1. Storing credentials in a PHP .ini file
; Configuration file to hold secret keys, account numbers and other useful
; strings for Amazon and other cloud accounts.

[amazon]
accessKey=0123456789ABCDEFGHIJ
secretKey=0123456789abcdefghiABCDEFGHI1234567890AB
ownerId=123456789012

SQS only uses your access key and secret key. You don't need to know your owner ID, but your owner ID becomes part of the queue name when you create a message queue.


About the sample application

The sample application consists of a single PHP page (sqs.php) that performs several functions:

  • Lists all the message queues in an account, including the number of messages in each one
  • Creates a message queue
  • Creates a message and puts it into a queue
  • Receives a message from a given queue
  • Deletes a received message
  • Deletes a message queue along with any messages in it.

To get things started, create a Zend_Service_Amazon_Sqs object.

Listing 2. Creating a Zend_Service_Amazon_Sqs object

Click to see code listing

Listing 2. Creating a Zend_Service_Amazon_Sqs object

require_once 'Zend/Service/Amazon/Sqs.php';
require_once 'Credentials.php';

$creds = new Credentials;
$sqs = new Zend_Service_Amazon_Sqs($creds->getCredential('amazon', 'accessKey'), $creds->getCredential('amazon', 'secretKey'));

This object lets you work with the queues associated with your account. The Zend_Service_Amazon_Sqs->getQueues() method returns an array of all the queue names owned by your account. The PHP page displays those in a table:

Figure 1. Listing your SQS queues
Screenshot showing the URLs of each queue and the number of messages each contains

The names of the message queues include the owner ID of your account. In this example, the queues belong to the owner ID 123456789012. You have to use the fully qualified queue name (http://queue.amazonaws.com/ownerId/queueName) when you access a queue or a message. The part of the table visible here also includes the number of visible messages in each queue. The PHP code looks like this:

Listing 3. Getting the list of queues and the number of messages in each
$queues = $sqs->getQueues();
foreach ($queues as $queue) {
  try {
 $messageCount = $sqs->count($queue);
    echo "<tr>";
    echo "<td>".$queue."</td>";
    echo "<td style='text-align: center;'>".$messageCount."</td>";

The code uses the count() method to see how many messages are in each queue. (To be precise, it's the approximate number of messages; more about that in a minute.) If the queue has at least one message, PHP creates a button to receive the next message; otherwise, the cell is blank (see Figure 2).

Listing 4. Creating a button to receive the next message
echo "<td>";
if ($messageCount) {
  echo "<form action='".$_SERVER['PHP_SELF']."' method='post'>";
  echo "<input type='hidden' name='getNextMessage' value='1'>";
  echo "<input type='hidden' name='queueToUse' value='$queue'/>";
 echo "<input type='submit' value='Receive Next Message'>";
  echo "</form>";
} 
else
  echo "&nbsp;";
 echo "</td>";

The final cell in each row of the table creates a button to delete the queue and any messages in it. The complete table of queues looks like Figure 2.

Figure 2. The complete table of queues
Expanded screenshot of the table of queues shows action buttons to receive messages, delete queues, and refresh the list

In this screen capture, there are three queues. The two queues that contain messages are displayed with a "Receive Next Message" button. Each row of the table has a "Delete Queue" button to delete a particular queue.


Creating a queue

Creating a queue is straightforward. Simply get the queue name and call the Zend_Service_Amazon_Sqs->create() method. The PHP page includes a simple form to enter a queue name:

Figure 3. Creating a queue
Screenshot showing creation of the groundhog_day queue; it has a title field and a creation button

The code to create a new queue is straightforward.

Listing 5. Creating a queue
try {
  $responseCode = $sqs->create($_POST['queueToCreate']);
  if ($responseCode)
    echo "The queue ".$_POST['queueToCreate']." was created successfully.";
  . . .
}
catch (Zend_Service_Amazon_SQS_Exception $sqse) {
  echo "The queue could not be created. The error message from Amazon is:";
  echo "<br/><br/><i>".$sqse->getMessage()."</i>";
}

Zend does not provide any special error handling for the create() method, so the code simply writes the details of the exception to the page if anything goes wrong. Creating a queue with an illegal name (queue#3, for example) returns the exception InvalidParameterValue, while creating one with a duplicate name returns QueueAlreadyExists. When the queue is created successfully, the page starts with a success message.

Listing 4. Queue created successfully
Screenshot of the success message

Creating a message

The PHP page also has a short form for creating a message.

Figure 5. Creating a message
Screenshot of the message-creation form showing a drop-down for queue selection, a text field to type the message, and a submission button

Notice that the drop-down list is populated with the queue names in your account.

Figure 6. Listing all of the queues in your account
Screenshot of the queue selection dropbox showing all available queues

The PHP code to build the drop-down list looks like Listing 6.

Listing 6. Creating a drop-down list of all the queues
<p>Select a queue:</p>
<select name="queueForNewMessage"> 
<?php
 foreach ($queues as $queue) { echo "<option>".$queue."</option>";
  }
?>
</select>
</code>

The code to create a new message uses the send() method.

Listing 7. Sending a message to a queue
try {
 $response = $sqs->send($_POST['queueForNewMessage'], $_POST['newMessage']);
  if ($response) {
    echo "The new message was successfully created in queue ";
    echo $_POST['queueForNewMessage'];
    echo ".<br/>The message ID is ".$response.".";
  }
  else {
    echo "The new message could not be created in queue ";
    echo $_POST['queueForNewMessage'];
    echo ".";
  }
}
catch (Zend_Service_Amazon_SQS_Exception $sqse) {
  echo "The message could not be created. The error message from Amazon is:";
  echo "<br/><br/><i>".$sqse->getMessage()."</i>";
}

The code sends the request to Amazon. If anything goes wrong while creating the message, the page displays an exception. In most cases, the page displays the ID of the successfully created message.

Figure 7. Message created successfully
Screenshot of the message creation success message that shows the queue used and the message ID string

The success message includes the ID of the new message. You'll see the message ID again later when you receive the message.


A few words about propagation latency

One of the issues in distributed systems like SQS is propagation latency. For the sake of performance and reliability, most cloud providers have multiple copies of your information scattered around their networks. The positive side of this design is that if a particular machine goes down, your information exists somewhere else in the network. The downside to this approach is that it takes some amount of time for changes to your information to make their way through the network. This delay is called propagation latency. If you install the sample application developed in this article, you'll notice its effects.

When you create a queue, the PHP page displays a success message, indicating that the queue was created successfully. The page also displays a table listing all of the queues in your account. The list of queues returned by SQS typically contains the queue you just created. On the other hand, if you create a message, the table of queues will almost certainly not display the correct number of messages because the message has not made its way to the queue. For example, if you create a new message in a queue that currently has three messages, the data returned by SQS will tell you the message was created successfully, and that there are only three messages in the queue.

To deal with this delay, the page contains a button to refresh the list of queues.

Figure 8. Refreshing the list of queues
Screenshot of the 'Refesh queue and message list' button

If you click this button to refresh the queue, at some point the table will contain the correct number of messages. (The refresh button allows the user to update the table without resubmitting the request to create a message.) For the sample application here, propagation latency can be a problem when you delete a queue. Even though SQS reports that it deleted the queue successfully, the name often shows up in the list. If you ask SQS for the number of messages in that queue, you'll get an exception. For that reason, the code that generates the list of queues uses a try block to get the number of messages in a queue. If the call to the count() method fails, the code simply ignores the exception.

To use SQS effectively, you need to keep the realities of propagation latency in mind. This applies to many other cloud services as well.


Receiving a message

There are two steps in processing a message in the queue: receiving it and deleting it. When a message is received, Amazon SQS marks that message as invisible. The message is yours to process, so anyone who accesses the queue won't see it. After you've received a message, it is your responsibility to delete the message within a certain period of time. Each queue is defined with a visibility timeout; if you don't delete the message within that time, the message becomes visible again and can be processed by anyone. The default visibility timeout for a queue is currently 30 seconds.

As an aside, when you create a queue, Amazon lets you define the visibility timeout for all processed messages. The Zend Framework supports a second parameter to the Zend_Service_Amazon_Sqs->create() method to define the visibility timeout.

Listing 8. Creating a queue with a specified visibility timeout
$responseCode = $sqs->create($_POST['queueToCreate'], 120);

In this example, the visibility timeout is 2 minutes.

Receiving a message from a queue is done with the Zend_Service_Amazon_Sqs->receive() method. The name of the message queue is passed in from the form. Because a message can be up to 8K characters long, it is displayed in an HTML <textarea> control. A received message has four parts:

  • The body, the text of the message itself
  • The md5 digest of the message body
  • The message_id, a unique identifier for the message
  • The handle, the identifier you must use to delete the message from the queue.

You can access the four parts of the message with the array keys indicated above. For example, you can use $message[0]['body'] to get the body of the message, while $message[0]['handle'] returns the message handle. Note that although Amazon SQS allows you to ask for more than one message at a time, the Zend Framework does not. Every call to Zend_Service_Amazon_Sqs->receive() returns a single message. The single message is returned in an array, however, so you have to use $message[0][...] to access the parts of the message.

Note: Some messaging systems allow you to look at a message without receiving it, an operation usually called peeking. Amazon SQS no longer allows you to peek at messages. The only way to see a message is to receive it.

When you click on the "Receive Next Message" button, you'll see something like Figure 9.

Figure 9. A received message
Screenshot of a received message showing the text and a delete button

The visibility timeout is used to generate the sentence, "It will go back into the queue in 30 seconds." More on queue attributes in a minute.

Figure 10. The message handle and the visibility timeout
Screenshot showing the message handle string and that, if not deleted, it will go back into the queue in 30 seconds

As mentioned, $message[0]['handle'] returns the handle of the message. You can use the getAttribute() method to return the visibility timeout.

Listing 9. Finding the visibility timeout for the queue
$visibilityTimeout = 
 $sqs->getAttribute($_POST['queueToUse'], 'VisibilityTimeout');

The visibility timeout is used to generate the sentence, "It will go back into the queue in 30 seconds." getAttribute() lets you find out various details of a queue; more on queue attributes in a minute.

The form that displays the received message is generated with this code.

Listing 10. Generating the form for a received message
echo "<form action='".$_SERVER['PHP_SELF']."' method='post'>";

// Display the message itself in a <textarea>
echo "The message from the queue is: <br/><br/>";
echo "<textarea cols='80' rows='8'>";
echo $message[0]['body'];
echo "</textarea><br/><br/>";

// The message handle and queue name are hidden fields
echo "<input type='hidden' name='deleteMessage' value='1'/>";
echo "<input type='hidden' name='messageHandle' ";
echo "value='".$message[0]['handle']."'>";
echo "<input type='hidden' name='queueToUse' ";
echo "value='".$_POST['queueToUse']."'>";

// The submit button deletes the message 
echo "To delete this message, click here: ";
echo "<input type='submit' value='Delete Message'><br/><br/>";

// Display the message handle if the user wants to delete it later
echo "If you want to delete this message ";
echo "later, use this message handle: <br/><br/>";
echo "<textarea cols='80' rows='3'>";
echo $message[0]['handle']."</textarea><br/><br/>";

// For information, display the visibility timeout of the queue
echo "If you do not delete this message, it will  ";
echo "go back into the queue in ".$visibilityTimeout." seconds.";
echo "</form>";

Deleting a message

As you might have noticed in the previous section, the form that displays a received message also contains a button to delete the message. The call to the Zend_Service_Amazon_Sqs->deleteMessage() method requires the queue name and the message handle.

Listing 11. Deleting a message from a queue
try {
 $response = $sqs->deleteMessage($_POST['queueToUse'], $_POST['messageHandle']);
  echo "The message was deleted successfully.";
}
catch (Zend_Service_Amazon_SQS_Exception $sqse) {
  echo "The message could not be deleted. The error message from Amazon is:";
  echo "<br/><br/><i>".$sqse->getMessage()."</i>";
}

If the message is deleted successfully, the page displays a message.

Figure 11. Successful message deletion
Screenshot showing the message successfully deleted

If anything goes wrong, the code simply displays an exception. (Creating a form to let the user delete a message by pasting in the message handle and queue name is left as an exercise for the reader.)


Getting the attributes of a queue

As you saw earlier, the PHP page displays the visibility timeout of a queue when you receive a message. This is done by calling getAttribute(). The first attribute of getAttribute() is the queue name. For the second argument, Amazon currently supports the following case-sensitive attribute names:

  • VisibilityTimeout— The visibility timeout for messages received from the queue.
  • ApproximateNumberOfMessages— The approximate number of messages currently in the queue. This does not include any messages that have been received.
  • ApproximateNumberOfMessagesNotVisible— The approximate number of messages that have been received but not yet deleted.
  • CreatedTimestamp— When the queue was created.
  • LastModifiedTimestamp— The last time the queue's attributes or permissions were changed. Sending, receiving or deleting a message does not change this timestamp.
  • All— Returns all attributes. This is the default.

Note: Be aware that if you call getAttribute() or getAttribute('All'), Zend currently returns the first attribute only. This bug is likely to be fixed in a future release. For now, if you want to get all of the attributes of a queue, you'll need to call getAttribute() for each one. You can generate a table listing all your queues and their attributes with the code in Listing 12.

Listing 12. Displaying all your queues and their attributes
<?php
  $queues = $sqs->getQueues();
  foreach ($queues as $queue) {
    try {
      echo "<tr>";
      echo "<td>".$queue."</td>";
      echo "<td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'VisibilityTimeout');
      echo "</td><td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'ApproximateNumberOfMessages');
      echo "</td><td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'ApproximateNumberOfMessagesNotVisible');
      echo "</td><td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'CreatedTimestamp');
      echo "</td><td style='text-align: center;'>";
      echo $sqs->getAttribute($queue, 'LastModifiedTimestamp')."</td>";
      echo "</tr>";
    }
    catch (Zend_Service_Amazon_SQS_Exception $sqse) {
    }
  }
?>

The table of attributes looks like this.

Figure 12. All the attributes of a queue
Screenshot of a table showing the queues and various attributes: visibility timeout, visible messages, invisible messages, created timestamp and modified timestamp

(This code is included in the samples as sqs-attributes.php.)


Deleting a queue

Deleting a queue deletes the queue and any messages it contains, including messages currently invisible. Because this is such a drastic operation, a confirmation dialog appears before a queue is actually deleted.

Figure 13. Deleting a queue must be confirmed
Screenstho showing a confirmation box to delete a queue.

When PHP generates the form to delete a queue, it defines the confirmation dialog with the onsubmit attribute of the <form> element.

Listing 13. Creating a button to delete the queue

Click to see code listing

Listing 13. Creating a button to delete the queue

echo "<td>";
echo "<form action='".$_SERVER['PHP_SELF']."' method='post' ";
echo "onsubmit='return confirm(\"Do you really want to delete the ";echo "queue $queue? This will delete all any messages in the queue ";echo "as well.\");'>";
echo "<input type='hidden' name='deleteQueue' value='1'/>";
echo "<input type='hidden' name='queueToDelete' value='$queue'/>";
echo "<input type='submit' value='Delete Queue'>";
echo "</form>";
echo "</td>";

If the user clicks the OK button to delete the queue, the queue and all of the messages it contains are deleted via the delete() method.

Listing 14. Deleting a queue
try {
 $response = $sqs->delete($_POST['queueToDelete']);
  echo "The queue was deleted successfully.";
}
catch (Zend_Service_Amazon_SQS_Exception $sqse) {
  echo "The queue could not be deleted. The error message from Amazon is:";
  echo "<br/><br/><i>".$sqse->getMessage()."</i>";
}

As with deleting a message, deleting a queue either displays a success message or an exception.

Figure 14. Successful queue deletion
Screenshot of success message after deleting a queue

If anything goes wrong, the code simply displays an exception.


Advanced topics

There are several operations supported by Amazon SQS that are not part of the Zend_Service_Amazon_Sqs class. We'll menion those briefly here, even though they're beyond the scope of the Zend Framework. To perform any of these tasks, you need to use one of the lower-level APIs provided by Amazon. The other operations are:

  • AddPermission: You can define permissions so that other users can access your queues. This allows you to use your queues as a way of coordinating work among different applications.
  • RemovePermission: You can revoke permissions, as well.
  • SetQueueAttributes: Zend allows you to get the attributes of a queue, but it does not allow you to change any of them.
  • ChangeMessageVisibility: After you have received a message, you can change its visibility timeout. This gives you more time to process the message before it returns to the queue. This method only applies to the received message; it does not change the default visibility timeout for the queue itself.

See the SQS documentation for more details on these methods.


Summary

This article presented a PHP page that lets you work with Amazon Simple Queue Service. You can use the page to create and delete message queues, send and receive messages, and monitor the status of the queues. The technical details of the actual requests sent to Amazon are hidden behind a PHP object, making it simple to use queues and messages. Using the Zend Framework gives you an elegant set of objects to work with cloud computing.


Download

DescriptionNameSize
Sample codeos-php-cloud3-source.zip5KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Cloud computing, Web development
ArticleID=477325
ArticleTitle=Cloud computing with PHP, Part 3: Using Amazon SQS with the Zend Framework
publish-date=03302010