Menu

Fun with Amazon's Simple Queue Service

January 5, 2005

Jason Levitt

Amazon.com has been exposing itself again, much to the delight of developers, entrepreneurs, and media junkies. This time, they've revealed Amazon Simple Queue Service (SQS), a basic message queue service with a web services interface. Originally developed and used in-house by internal Amazon developers, the API is now publicly exposed so that everyone can join in the fun.

Message queues are normally the stuff of big-business middleware and operating system internals, but when you have easy access to a high-performance, high-bandwidth, network-accessible message queue service with a simple API, well, there are a lot of potential applications. Importantly, Simple Queue Service 1.0, which is in beta now, is free for developers to play with. Amazon will start charging for use when it is released (although no price has been set, I'm told that it will be available at "a low cost that will not restrict innovation," whatever that means). But for now, it's totally free, so let's check it out.

Accessing Amazon Web Services

Like other Amazon Web Services, you can access Simple Queue Service in three different ways: by using an XML-over-HTTP (what Amazon calls a REST) interface, a SOAP interface, or by taking advantage of Amazon's XSLT engine. For this article, I'm focusing on using the REST API. But, before you can access any of Amazon's Web Services, you need to obtain an Amazon Subscription ID. Don't worry, it's totally free. You can get one here. The subscription ID is used by Amazon to generate usage statistics and to identify developers who may attempt to abuse their generous free offerings. What constitutes abuse or inappropriate use of the various Amazon Web Services? Read the license agreement. I'm not a lawyer, but basically, no porn and don't average more than one request per second. Capiche? Failure to adhere to the license agreement can get your originating IP address blacklisted by Amazon.

The API

The API for Amazon Simple Queue Service is, as the name suggests, quite simple and easy to use. Their are seven methods (Amazon calls them "operations," which is what I'll call them) which are summarized in table 1-1. For more specific details, you can refer to Amazon's online documentation.

Table 1-1 Amazon Simple Queue Service Operations
Operation Description
CreateQueue Create a message queue
DeleteQueue Delete a message queue
ListMyQueues List my messsage queues
Read Read an entry, or entries, from a queue
Enqueue Add an entry to a queue
Dequeue Delete an entry, or entries, from a queue
ConfigureQueue Modify details about a queue

Structure of Simple Queue Service Requests Using REST

Using Amazon's REST interface, I could demonstrate the entire API without using a programming language at all. That's because Amazon chose to implement SQS using only HTTP GET requests (no PUTs, DELETEs, or POSTs). I could simply construct the appropriate URLs and put them into my favorite web browser to execute them. While some might disagree with this design (which is precisely what Joe Gregorio has done in this week's The Restful Web column-- Editor) about Amazon's non-RESTy choice to use only HTTP GETs for SQS, the fact is that it makes life very simple for developers. All SQS REST requests have the same basic URL structure:

http:/webservices.amazon.com/onca/xml?Service=AWSSimpleQueueService&

    SubscriptionId=[Your Subscription ID Here]&

Version=[Version number]&Operation=[Operation from Table 1-1]

    &[some parameter]=[some value]&[some parameter]=[some value]... 

A few things to point out about the SQS request structure:

  • All requests start with the same prefix: http:/webservices.amazon.com/onca/xml?Service=AWSSimpleQueueService
  • All requests require a Subscription ID: SubscriptionId=001VHHVC74XFD88KCY82
  • Though optional, it's a good idea to include the Version of Simple Queue Service that you're using: Version=2004-10-14. Yes, the version is a date. October 14th, 2004 is the first version of Simple Queue Service. Subsequent versions will have newer dates. To find the date of the latest version, look at the date in the targetNamespace string in the SQS WSDL.
  • All requests must specify an operation from Table 1-1. For example: Operation=CreateQueue
  • All requests are case-sensitive. If you use Operation=createqueue instead of Operation=CreateQueue, the request will fail

Simple Queue Service Design and Limitations

In SQS, a queue is a list of entries. An entry is a blob of data. When you create a queue, it's empty until you put entries on it. You can then read the entries you put on the queue. Entries remain on the queue until you explicitly delete them. The ordering of the queue is FIFO (First In, First Out). However, because access to the queues is heavily cached for performance reasons, Amazon does not guarantee FIFO access--occasionally, SQS requests may return results in a slightly different order than FIFO.

You may specify a Read Lock on any queue you create. The Read Lock specifies how long (in seconds) an entry in a queue will be unavailable to subsequent read operations after it is returned by a read operation. The default Read Lock for queues is 60 seconds. The minimum value is 0 seconds. Read Lock can be thought of as an advisory locking mechanism that's useful for cases where you may have several processes reading from a queue, but you only want one process to handle a particular entry.

Each queue you create is tied to your Subscription ID. You can only access queues that were created by your Subscription ID. So, if you want to make sure that others don't access your queues, you need to make sure that they don't find out your Subscription ID. For more privacy, you can make requests via HTTPS.

It'd be way cool if I could create millions of queues stuffed with my favorite song lyrics, or my copious notes about the bogus information in Texas high school history textbooks, but, while Simple Queue Service may be free for the moment, it's not that generous. When using SQS, the following limitations apply to all queues created by a single Subscription ID:

  • Maximum number of queues you can create: unlimited (This is what the Amazon folks tell me--care to test their assertion?)
  • Total number of queue entries: 4000 (combined total of all your queues)
  • Maximum size of a single queue entry: 4Kbytes
  • Maximum length of a Readlock: 30 days (2,592,000 seconds)

Creating a Queue

You can create a queue named "Jason" by dereferencing the following URL (broken across lines for readability). If you don't replace my Subscription ID, 001VHHVC74XFD88KCY82, with your own, then this request will generate an error because I (or someone else reading this article) already created the queue.

http:/webservices.amazon.com/onca/xml?Service=AWSSimpleQueueService

    &Version=2004-10-14&SubscriptionId=001VHHVC74XFD88KCY82

    &Operation=CreateQueue&QueueName=Jason

If it succeeds, you'll see this in your web browser:


<?xml version="1.0" encoding="UTF8"?>

<CreateQueueResponse 

  xmlns="http://webservices.amazon.com/AWSSimpleQueueService/2004-10-14">

  <OperationRequest>

    <HTTPHeaders>

      <Header Name="UserAgent" Value="Mozilla/4.0 (compatible; MSIE 6.0; 

      Windows NT 5.1)"/>

    </HTTPHeaders>

    <RequestId>054FT186J7SQ6CKZDJC8</RequestId>

    <Arguments>

      <Argument Name="Service" Value="AWSSimpleQueueService"/>

      <Argument Name="QueueName" Value="Jason"/>

      <Argument Name="SubscriptionId" Value="[Your Subscription Id]"/>

      <Argument Name="Version" Value="2004-10-14"/> 

      <Argument Name="Operation" Value="CreateQueue"/>

    </Arguments>

  </OperationRequest>

  <CreateQueueResult>

    <Request>

      <IsValid>True</IsValid>

      <CreateQueueRequest>

        <QueueName>Jason</QueueName>

      </CreateQueueRequest>

    </Request>

    <QueueId>0KJ2NTM8MW1QNJQY2YZB</QueueId>

  </CreateQueueResult>

</CreateQueueResponse>

If you didn't replace my Subscription ID with yours, you might see something like this:


<?xml version="1.0" encoding="UTF-8"?>

<CreateQueueResponse 

 xmlns="http://webservices.amazon.com/AWSSimpleQueueService/2004-10-14">

  <OperationRequest>

    <HTTPHeaders>

      <Header Name="UserAgent" Value="Mozilla/4.0 (compatible; MSIE 6.0;

       Windows NT 5.1)"/>

    </HTTPHeaders>

    <RequestId>04CGJDQDS8A1QK5091N6</RequestId>

    <Arguments>

      <Argument Name="Service" Value="AWSSimpleQueueService"/>

      <Argument Name="QueueName" Value="Jason"/>

      <Argument Name="SubscriptionId" Value="001VHHVC74XFD88KCY82"/>

      <Argument Name="Version" Value="2004-10-14"/> 

      <Argument Name="Operation" Value="CreateQueue"/>

    </Arguments>

  </OperationRequest>

  <CreateQueueResult>

    <Request>

      <IsValid>True</IsValid>

      <CreateQueueRequest>

        <QueueName>Jason</QueueName>

      </CreateQueueRequest>

    </Request>

    <SimpleQueueServiceError>

      <ErrorCode>AWS.SimpleQueueService.QueueNameExists</ErrorCode>

      <ReasonText>

       A queue with that name already exists for this subscription.

      </ReasonText>

    </SimpleQueueServiceError>

    <QueueId>0KJ2NTM8MW1QNJQY2YZB</QueueId>

  </CreateQueueResult>

</CreateQueueResponse>

Let's talk about a few notable things revealed by these responses.

First, note that all responses are UTF-8 encoded. Your requests should also be UTF-8 encoded.

<?xml version="1.0" encoding="UTF-8"?>

The operation we used, along with the word "Response", and the default namespace identifier are returned next:

<CreateQueueResponse 

 xmlns="http://webservices.amazon.com/AWSSimpleQueueService/2004-10-14">

The OperationRequest block is next. The HTTP UserAgent header is echoed back. The RequestId is a unique ID that is generated for each request by Amazon. If you encounter serious problems with Amazon Queue Service, you can report this ID to Amazon. Your request arguments are then echoed back. These are useful if you are using XSLT style sheets and want to pass parameters into your style sheet from the request.


 <OperationRequest>

    <HTTPHeaders>

      <Header Name="UserAgent" Value="Mozilla/4.0 (compatible; MSIE 6.0;

       Windows NT 5.1)"/>

    </HTTPHeaders>

    <RequestId>04CGJDQDS8A1QK5091N6</RequestId>

    <Arguments>

      <Argument Name="Service" Value="AWSSimpleQueueService"/>

      <Argument Name="QueueName" Value="Jason"/>

      <Argument Name="SubscriptionId" Value="001VHHVC74XFD88KCY82"/>

      <Argument Name="Version" Value="2004-10-14"/> 

      <Argument Name="Operation" Value="CreateQueue"/>

    </Arguments>

 </OperationRequest>

The actual results are in the final block, which has the container element CreateQueueResult, the operation name plus the word "Result." The "Request" block that follows is just your request arguments echoed back. The IsValid tag is always present and has the value of either "True" or "False." If it's "True," Amazon's server considers your request valid, which means that the syntax is correct. If it's "False," then Amazon's server found a problem with your request syntax. The container tag CreateQueueRequest contains the CreateQueue operation parameters.

Following the Request block is the actual response, in this case, the Queue ID of the queue created by Amazon.


<CreateQueueResult>

    <Request>

      <IsValid>True</IsValid>

      <CreateQueueRequest>

        <QueueName>Jason</QueueName>

      </CreateQueueRequest>

    </Request>

    <QueueId>0KJ2NTM8MW1QNJQY2YZB</QueueId>

</CreateQueueResult>

Had the request failed, as in the second example above, the CreateQueueResult block would look like this:


 <CreateQueueResult>

    <Request>

      <IsValid>True</IsValid>

      <CreateQueueRequest>

        <QueueName>Jason</QueueName>

      </CreateQueueRequest>

    </Request>

    <SimpleQueueServiceError>

      <ErrorCode>AWS.SimpleQueueService.QueueNameExists</ErrorCode>

      <ReasonText>

       A queue with that name already exists for this subscription.

      </ReasonText>

    </SimpleQueueServiceError>

    <QueueId>0KJ2NTM8MW1QNJQY2YZB</QueueId>

 </CreateQueueResult>

The request was still a valid request (IsValid is "True"), but since a queue with the name "Jason" already existed for that Subscription ID, the request failed. Queue names must be unique for a given Subscription ID. When a request fails, a SimpleQueueService Error block appears instead of the QueueId. An Error block always contains an ErrorCode and a ReasonText. A complete list of possible error codes is available in the documentation.

Placing an Entry on a Queue

In this next example, I place two entries on the queue named "Jason." The first entry is the string "Dude, what are your doing?" and the second entry is the string "sheer poetry." The operation is called Enqueue.

http://webservices.amazon.com/onca/xml

?Service=AWSSimpleQueueService&Version=2004-10-14

&SubscriptionId=001VHHVC74XFD88KCY82

&Operation=Enqueue&QueueName=Jason

&QueueEntryBody.1=Dude,%20what%20are%20you%20doing?

&QueueEntryBody.2=sheer%20poetry

If this request succeeds, then you'll see a response like this:


....

   ....

  <EnqueueResult>

    <Request>

      <IsValid>True</IsValid>

      <EnqueueRequest>

        <QueueName>Jason</QueueName>

        <QueueEntryBodies>

          <QueueEntryBody>Dude, what are you doing?</QueueEntryBody>

          <QueueEntryBody>sheer poetry</QueueEntryBody>

        </QueueEntryBodies>

      </EnqueueRequest>

    </Request>

    <Status>SUCCESS</Status>

  </EnqueueResult>

The actual response from Amazon, assuming the request is valid and has no logic errors, is a single Status tag with a value of "SUCCESS." If the request failed for some reason, then an Error block would appear with the appropriate error code.

Reading Queue Entries

To read entries from a queue, we only need to know the name of the queue we created. Alternatively, we could use the QueueId that was returned by our CreateQueue call. You can specify up to 25 entries to read from a queue in one request by using the ReadCount parameter. Here, we just want to read the two entries we put on the queue.

http://webservices.amazon.com/onca/xml

  ?Service=AWSSimpleQueueService&Version=2004-10-14

  &SubscriptionId=001VHHVC74XFD88KCY82&Operation=Read

  &QueueName=Jason&ReadCount=2

....

  ....

  <ReadResult>

    <Request>

      <IsValid>True</IsValid>

      <ReadRequest>

        <QueueName>Jason</QueueName>

        <ReadCount>2</ReadCount>

      </ReadRequest>

    </Request>

    <QueueEntries>

      <QueueEntry>

        <QueueEntryId>

        0CSZ9B047F84K9G1SW7S|0QY2R0SBDXWVW87QG8ZD|100T0A28JX6EW1W4MYYF

        </QueueEntryId>

        <QueueEntryBody>Dude, what are you doing?</QueueEntryBody>

      </QueueEntry>

      <QueueEntry>

        <QueueEntryId>

        0ESP6SZGBPJEHNZ2V649|0QY2R0SBDXWVW87QG8ZD|100T0A28JX6EW1W4MYYF

        </QueueEntryId>

        <QueueEntryBody>sheer poetry</QueueEntryBody>

      </QueueEntry>

    </QueueEntries>

  </ReadResult>

Note that the entries come back in the same order they were put on the queue, e.g. FIFO, and that each entry has a corresponding QueueEntryId. Because I created the queue with the default Read Lock of 60 seconds, refreshing my browser window, and thus executing this again, should yield an Error block that indicates no results (typically, though, because of caching effects on the Amazon server side, the same entries are sometimes returned).


<SimpleQueueServiceError>

 <ErrorCode>AWS.SimpleQueueService.NoData</ErrorCode> 

 <ReasonText>Success, but no data was found in the queue.</ReasonText> 

</SimpleQueueServiceError>

Deleting Queue Entries

In order to delete an entry from a queue, we need the QueueEntryIds that are returned from the previous Read operation. The operation is called Dequeue:


http://webservices.amazon.com/onca/xml

?Service=AWSSimpleQueueService&Version=2004-10-14

&SubscriptionId=001VHHVC74XFD88KCY82&Operation=Dequeue&QueueName=Jason

&QueueEntryId.1=0CSZ9B047F84K9G1SW7S|0QY2R0SBDXWVW87QG8ZD|100T0A28JX6EW1W4MYYF

&QueueEntryId.2=0ESP6SZGBPJEHNZ2V649|0QY2R0SBDXWVW87QG8ZD|100T0A28JX6EW1W4MYYF

Like the Enqueue operation, a successful result just yields "SUCCESS":


....

....

<DequeueResult>

    <Request>

      <IsValid>True</IsValid>

      <DequeueRequest>

        <QueueName>Jason</QueueName>

        <QueueEntryIds>

          <QueueEntryId>

          0CSZ9B047F84K9G1SW7S|0QY2R0SBDXWVW87QG8ZD|100T0A28JX6EW1W4MYYF

          </QueueEntryId>

          <QueueEntryId>

          0ESP6SZGBPJEHNZ2V649|0QY2R0SBDXWVW87QG8ZD|100T0A28JX6EW1W4MYYF

          </QueueEntryId>

        </QueueEntryIds>

      </DequeueRequest>

    </Request>

    <Status>SUCCESS</Status>

  </DequeueResult>

A Chat Application Using Simple Queue Services

I tried to think "out of the box" for my sample SQS application. Why not a chat application? It makes perfect sense, or no sense at all, depending on your perspective. I'm also a big fan of Google's Gmail application, which is one of the coolest cross-platform Javascript applications ever created. I decided to use the XmlHTTPRequest object and the DOM Level 3 capabilities of Mozilla and Internet Explorer to craft my application. My chat application, which I call sqschat, actually runs off a file from your hard disk and doesn't require a web server at all (IE users may have to right-click that link and save to local disk). It does, however, require the following:

  • Either Internet Explorer 6 on Windows or a recent Mozilla browser (Firefox 1.0 or Netscape 7.2 works fine). Sorry, Safari 1.24 doesn't have DOM Level 3 (yet).
  • The files sarissa.js and sarissa_ieemu_xpath.js from the open source Javascript library Sarissa. Sarissa provides a Javascript compatability layer to smooth over the differences between Microsoft's XmlHTTPRequest and DOM implementations and the ones used by Mozilla and other DOM Level 3 compliant browsers. Get Sarissa here. (I used Sarissa version 0.9.4.2).

You should be able to run this application from your hard drive with no problem. You may have to dumb down the security settings on Internet Explorer, and Mozilla browsers require that you respond to a dialog box that warns you of accesses over the internet. You cannot run this file from a web server under Mozilla without digitally signing it first.

Application Design

My chat application takes advantage of the fact that Amazon SQS queues must have unique names (under a particular Subscription ID), and that you can search for queues using a prefix of the queue name. All users must be using the same Subscription ID so that they can access each others' queues. Each person in the chat has a single queue from which they read messages. The name of the queue is the name of the chat room appended to the name the user chooses to chat with. So, if Simon and Jason are chatting in the "lounge," Simon has a queue named "loungeSimon," and Jason has a queue named "loungeJason." When Simon says something in the chat room, the text is echoed to his screen and also placed on Jason's queue. Meanwhile, an endless loop keeps reading from Simon's queue in order to receive messages from Jason. After Simon reads a message from his queue, he deletes it. When he exits chat, his queue is deleted.

To find all the users currently chatting in the lounge, I do a ListMyQueues call with Prefix=lounge. This call will return all queues with a name starting with the string "lounge." I can then use this list of queue names to send my messages to everyone in the chat room.

Code Details

All of the heavy lifting in this application is done by a single function that I call makeHTTPrequest:


function makeHTTPrequest(targetURL) {

   // Set security -- only needed for Mozilla

   if(!_SARISSA_IS_IE){

     netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');

   }

   // Get the HTTP request object

   var reqObj = Sarissa.getXmlHttpRequest();

   // Open the REST request, flag it as a synchronous request

   reqObj.open("GET", targetURL, false);

   // Send a header to force IE not to cache

   reqObj.setRequestHeader('If-Modified-Since','Sun, 31 Dec 2000 20:20:20 CST');

   // Make a synchronous request

   reqObj.send(null);

   // Return the results

   return reqObj;

}

The function takes an operation URL as an argument and returns the completed request object. The first thing I do is set Mozilla's UniversalBrowserRead privilege which lets us make HTTP requests outside of our machine. The constant _SARISSA_IS_IE is created by Sarissa and is a convenient way to test if we're using (or not using) IE. The actual HTTP request is made using Sarissa's cross-platform XmlHTTPRequest object. For simplicity sake, I use the synchronous version (the "false" in reqObj.open) rather than the asynchronous version. To make this more robust, choose the asynchronous version and catch any exceptions that occur.

The If-Modified-Since header is needed to force IE to not cache GET results. Without this header, IE often returns the same results over and over. Mozilla ignores the header and doesn't cache the requests.

A few important constants I use over and over are the Subscription ID, the name of the chat room, and the version of SQS that we're using:


var subscriptionId = "001VHHVC74XFD88KCY82"; // You subscription id

var chatroom = "poolhall";                   // The name of the chat room

var version = "2004-10-14";                  // The version of Amazon Queue 

                                                Service to use

Some pre-defined Xpath paths also come in handy for pulling data out of the responses from Amazon:


  // path to queue names

  var whoPath = "//aws:ListMyQueuesResult/aws:Queues/aws:Queue[*]/aws:QueueName";

  // path to Error code

  var errorPath = "//aws:ReadResult/aws:SimpleQueueServiceError/aws:ErrorCode";

  // path to queue entries

  var entryPath = "//aws:ReadResult/aws:QueueEntries/aws:QueueEntry[*]/aws:

     QueueEntryBody";

  // path to queue entry ids

  var idPath = "//aws:ReadResult/aws:QueueEntries/aws:QueueEntry[*]/aws:

     QueueEntryId";

The paths use a default namespace that I made up, called "aws". I define the default namespace for all my DOM documents using the targetNamespace from the Amazon WSDL. The version must match the version used in the REST requests.

// the generic DOM document

var domDoc = Sarissa.getDomDocument();

// set the default namespace to Amazon's default

Sarissa.setXpathNamespaces

  (domDoc, "xmlns:aws='http://webservices.amazon.com/AWSSimpleQueueService/" + 

   version + "'");

I start the script by getting the user's chat name from them and then creating their queue. I create the queue with a Read Lock timeout of 0 seconds, since there will be no one reading from my queue except for me and I always want queue entries returned immediately.


// Get the user's chat handle

var d = new Date();

var handle= prompt("Enter your chat name: ", " ");   

if ( (handle == ' ') || ( handle == null) )  {     

   // Anonymous chatters are Noname + time in seconds      

   handle="Noname" + d.getTime();

}

   

// Create the user's chat queue

var initUrl = "http://webservices.amazon.com/onca/xml?

  Service=AWSSimpleQueueService&Version=" + version + "&SubscriptionId=" + 

  subscriptionId + "&Operation=CreateQueue&ReadLockTimeoutSeconds=0&QueueName=" + 

  chatroom + handle;

var initcall = Sarissa.getXmlHttpRequest();

makeHTTPrequest(initUrl);

I then get a list of all the queues which have a prefix starting with the chat room name, which is the same as getting a list of all the people who are currently chatting in that chat room. I then create a DOM document out of the results and apply the whoPath Xpath query to get the list.


// Get the initial list of people in the chat

var inchatUrl ="http://webservices.amazon.com/onca/xml

  ?Service=AWSSimpleQueueService&Version=" + version + 

  "&SubscriptionId=" + subscriptionId + "&Operation=ListMyQueues

  &QueueNamePrefix=" + chatroom;

whocall=makeHTTPrequest(inchatUrl);



// Find the online users by their QueueName

// domDoc is parsed in the HTML at the bottom of the script

domDoc.loadXML(whocall.responseText);

nameList = domDoc.selectNodes(whoPath);

I cycle through the nameList later in the HTML in order to display the initial list of people chatting in the chat room.


div = document.getElementById("online");

div.innerHTML = "<b>Currently talking in chat room " + chatroom +": </b><br />";

for(i=0;i < nameList.length;i++) {

   n = Sarissa.getText(nameList[i]);

   div.innerHTML = div.innerHTML + "<b> " + n.substring(clen) + " </b>";

}

The rest of the application has two parts. One part is this loop that continually runs checkForever(), a routine that checks for new people (queues) that are entering the chat room and also grabs any incoming messages.


var ourInterval = window.setInterval("checkForever()", checkinterval);

The other part gets executed when you enter text into the text form field that I provide. When you enter a message into the chat, I put it on all the other chat members queues by cycling through the nameList:


for(i=0;i < nameList.length;i++) {

      n = Sarissa.getText(nameList[i]);

      if (n.substring(clen) == handle) continue;

      entry = encodeURIComponent("" + handle + "" + " > " + tin + "<br />");

      enqueueUrl="http://webservices.amazon.com/onca/xml 

        ?Service=AWSSimpleQueueService&Version=" + version + 

        "&SubscriptionId=" + subscriptionId + "&Operation=Enqueue

        &QueueName=" + n + "&QueueEntryBody.1=" + entry;

     makeHTTPrequest(enqueueUrl);      

   }

Retrieving incoming messages requires two calls. In the first call, I retrieve as many entries as possible from my queue. The SQS API lets you retrieve up to 25 messages per request by specifying ReadCount=25.


// Get any msgs from my queue

   myqueueUrl="http://webservices.amazon.com/onca/xml

     ?Service=AWSSimpleQueueService&Version=" + version + 

     "&SubscriptionId=" + subscriptionId + "&Operation=Read

     &QueueName=" + chatroom + handle + "&ReadCount=25";

   enqcall=makeHTTPrequest(myqueueUrl);

I then create a DOM document with the response and use Xpath requests to collect all the queue entries and all the queue entry IDs.

  

   domDoc.loadXML(enqcall.responseText);

   entryList = domDoc.selectNodes(entryPath);

   idList = domDoc.selectNodes(idPath);

Displaying the incoming messages is just a matter of cycling through the entryList and referencing the appropriate div tag:


// Output other people's noise

   div = document.getElementById("thechat");

   for(i=0;i < entryList.length;i++) {

      e = Sarissa.getText(entryList[i]);

      f = decodeURIComponent(e);

      div.innerHTML = div.innerHTML + f;

   }

Finally, I go through the idList and use the queue IDs to build the parameter list for the REST request that deletes the entries from my queue.I delete them so that subsequent read requests do not return them and also so that I can delete the user's queue when they exit (queues cannot be deleted unless they are empty).


// Remove msgs from my queue

   urlSuffix = '';

   for(i=0;i < idList.length;i++) {

      count = i + 1;

      urlSuffix = urlSuffix + '&QueueEntryId.'+ count + '=' + 

        Sarissa.getText(idList[i]);

   } 

   if (urlSuffix != '') {

      myqueueUrl="http://webservices.amazon.com/onca/xml

        ?Service=AWSSimpleQueueService&Version=" + version + 

        "&SubscriptionId=" + subscriptionId + "&Operation=Dequeue

        &QueueName=" + chatroom + handle + urlSuffix;

      makeHTTPrequest(myqueueUrl);

   }

I do an onUnload event on the body tag to try to delete the user's queue when they exit. Unfortunately, it only works if the user keeps the window open and navigates to another web page. If the user closes the window, it doesn't get executed, and the user's queue persists. Having a special 'exit chat' button is a better idea.


function Cleanup() {   

   var cleanupUrl = "http://webservices.amazon.com/onca/xml

     ?Service=AWSSimpleQueueService&Version=" + version + 

     "&SubscriptionId=" + subscriptionId + "&Operation=DeleteQueue

     &QueueName=" + chatroom + handle;

   makeHTTPrequest(cleanupUrl);

}

Redux

Amazon Simple Queue Services is indeed simple, and this application hardly stresses the full capabilities of it. But it does prove the general-purpose nature of SQS--how it can be applied to applications other than the usual business middleware. For more SQS code samples, visit Amazon's code samples page.