Compare commits
23 commits
bandalore-
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0fb4273b2 | ||
|
|
478210ccb2 | ||
|
|
e4a15227f6 | ||
|
|
09e7772fd7 | ||
|
|
42751b891a | ||
|
|
daffed7bcc | ||
|
|
ce8c02bdc4 | ||
|
|
98cb434787 | ||
|
|
bfb0fca2e7 | ||
|
|
e9f1afbb50 | ||
|
|
3d1c859c62 | ||
|
|
382fd20418 | ||
|
|
960c5e4966 | ||
|
|
b7d186125c | ||
|
|
e31c010c08 | ||
|
|
14b7b05b70 | ||
|
|
e4fe404f72 | ||
|
|
5a84c6d71b | ||
|
|
a2fc3400bc | ||
|
|
21ed5eb278 | ||
|
|
48c5f17ad5 | ||
|
|
b76312303a | ||
|
|
47b44e7555 |
4 changed files with 77 additions and 17 deletions
49
README.md
49
README.md
|
|
@ -14,17 +14,17 @@ Bandalore is available in Maven central. Add it to your Maven project's `pom.xm
|
|||
<dependency>
|
||||
<groupId>com.cemerick</groupId>
|
||||
<artifactId>bandalore</artifactId>
|
||||
<version>0.0.2</version>
|
||||
<version>0.0.6</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
or your leiningen project.clj:
|
||||
|
||||
```clojure
|
||||
[com.cemerick/bandalore "0.0.2"]
|
||||
[com.cemerick/bandalore "0.0.6"]
|
||||
```
|
||||
|
||||
Bandalore is compatible with Clojure 1.2.0 - 1.4.0.
|
||||
Bandalore is compatible with Clojure 1.2.0+.
|
||||
|
||||
## Logging
|
||||
|
||||
|
|
@ -54,6 +54,19 @@ to do anything:
|
|||
(def client (sqs/create-client "your aws id" "your aws secret-key"))
|
||||
```
|
||||
|
||||
**Security Note** If your application using Bandalore is deployed to EC2, _you
|
||||
should not put your AWS credentials on those EC2 nodes_. Rather,
|
||||
[give your EC2 instances IAM roles](http://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/java-dg-roles.html),
|
||||
and use the nullary arity of `create-client`:
|
||||
|
||||
```clojure
|
||||
(require '[cemerick.bandalore :as sqs])
|
||||
(def client (sqs/create-client))
|
||||
```
|
||||
|
||||
This will use credentials assigned to your EC2 node based on its
|
||||
role that are automatically rotated.
|
||||
|
||||
You can create, delete, and list queues:
|
||||
|
||||
```clojure
|
||||
|
|
@ -95,6 +108,28 @@ That's cleaner than having to interop directly with the Java SDK, but it's all
|
|||
pretty pedestrian stuff. You can do more interesting things with some
|
||||
simple higher-order functions and other nifty Clojure facilities.
|
||||
|
||||
### Enabling SQS Long Polling
|
||||
|
||||
[Long polling](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-long-polling.html) reduces the number of empty responses by allowing Amazon SQS service to wait until a message is available in the queue before sending a response. You can enable long polling on an individual receive request by supplying the optional kwarg `:wait-time-seconds`:
|
||||
|
||||
:wait-time-seconds - time in seconds (bewteen 0 and 20) for SQS to wait if there are no messages in the queue. A value of 0 indicates no long polling.
|
||||
|
||||
```clojure
|
||||
; ensure our queue is empty to start
|
||||
#> (get (sqs/queue-attrs client q) "ApproximateNumberOfMessages")
|
||||
"0"
|
||||
#> (let [no-polling (future (sqs/receive client q))
|
||||
long-polling (future (sqs/receive client q :wait-time-seconds 20))]
|
||||
(Thread/sleep 10000) ;; Sleep 10s before sending message
|
||||
(sqs/send client q "my message body")
|
||||
(println (count @no-polling))
|
||||
(println (count @long-polling)))
|
||||
0
|
||||
1
|
||||
nil
|
||||
|
||||
```
|
||||
|
||||
### Sending and receiving Clojure values
|
||||
|
||||
SQS' message bodies are strings, so you can stuff anything in them that you can
|
||||
|
|
@ -222,7 +257,7 @@ and another consumes those messages using a lazy seq provided by `polling-receiv
|
|||
#> (defn consume-dummy-messages
|
||||
[client q]
|
||||
(future (dorun (map (sqs/deleting-consumer client (comp println :body))
|
||||
(sqs/polling-receive client q :max-wait Integer/MAX_VALUE :limit 10)))))
|
||||
(sqs/polling-receive client q :max-wait Long/MAX_VALUE :limit 10)))))
|
||||
#'cemerick.bandalore-test/consume-dummy-messages
|
||||
#> (consume-dummy-messages client q) ;; start the consumer
|
||||
#<core$future_call$reify__5500@a6f00bc: :pending>
|
||||
|
|
@ -264,13 +299,13 @@ Since the tests are live, you either need to add your AWS credentials to your
|
|||
using `-D` switches:
|
||||
|
||||
```
|
||||
$ mvn -Daws.id#XXXXXXX -Daws.secret-key#YYYYYYY clean install
|
||||
$ mvn -Daws.id=XXXXXXX -Daws.secret-key=YYYYYYY clean install
|
||||
```
|
||||
|
||||
Or, you can skip the tests entirely:
|
||||
|
||||
```
|
||||
$ mvn -Dmaven.test.skip#true clean install
|
||||
$ mvn -Dmaven.test.skip=true clean install
|
||||
```
|
||||
|
||||
In any case, you'll find a built `.jar` file in the `target` directory, and in
|
||||
|
|
@ -284,6 +319,6 @@ or would like to contribute patches.
|
|||
|
||||
## License
|
||||
|
||||
Copyright © 2011-2012 Chas Emerick
|
||||
Copyright © 2011-2013 Chas Emerick and contributors.
|
||||
|
||||
Licensed under the EPL. (See the file epl-v10.html.)
|
||||
|
|
|
|||
4
pom.xml
4
pom.xml
|
|
@ -2,7 +2,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.cemerick</groupId>
|
||||
<artifactId>bandalore</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.7-SNAPSHOT</version>
|
||||
<name>bandalore</name>
|
||||
<description>A Clojure library for Amazon's Simple Queue Service (SQS).</description>
|
||||
<url>http://github.com/cemerick/bandalore</url>
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk</artifactId>
|
||||
<version>1.3.21.1</version>
|
||||
<version>1.8.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
(defn create-client
|
||||
"Creates a synchronous AmazonSQSClient using the provided account id, secret key,
|
||||
and optional com.amazonaws.ClientConfiguration."
|
||||
([]
|
||||
(create-client (com.amazonaws.ClientConfiguration.)))
|
||||
([client-config]
|
||||
(AmazonSQSClient.
|
||||
(.withUserAgent client-config "Bandalore - SQS for Clojure")))
|
||||
([id secret-key]
|
||||
(create-client id secret-key (com.amazonaws.ClientConfiguration.)))
|
||||
([id secret-key client-config]
|
||||
|
|
@ -45,9 +50,10 @@
|
|||
(.deleteQueue client (DeleteQueueRequest. queue-url)))
|
||||
|
||||
(defn list-queues
|
||||
"Returns a seq of all queues' URL strings."
|
||||
[^AmazonSQSClient client]
|
||||
(->> (ListQueuesRequest.)
|
||||
"Returns a seq of all queues' URL strings. Takes an optional string prefix
|
||||
argument to only list queues with names that start with the prefix."
|
||||
[^AmazonSQSClient client & {:keys [prefix]}]
|
||||
(->> (ListQueuesRequest. prefix)
|
||||
(.listQueues client)
|
||||
.getQueueUrls
|
||||
seq))
|
||||
|
|
@ -100,6 +106,11 @@
|
|||
Defaults to the empty set (i.e. no attributes will be included in
|
||||
received messages).
|
||||
See the SQS documentation for all support message attributes.
|
||||
:wait-time-seconds - enables long poll support. time is in seconds, bewteen
|
||||
0 (default - no long polling) and 20.
|
||||
Allows Amazon SQS service to wait until a message is available
|
||||
in the queue before sending a response.
|
||||
See the SQS documentation at (http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-long-polling.html)
|
||||
|
||||
Returns a seq of maps with these slots:
|
||||
|
||||
|
|
@ -110,13 +121,17 @@
|
|||
:receipt-handle - the ID used to delete the message from the queue after
|
||||
it has been fully processed.
|
||||
:source-queue - the URL of the queue from which the message was received"
|
||||
[^AmazonSQSClient client queue-url & {:keys [limit visibility ^java.util.Collection attributes]
|
||||
[^AmazonSQSClient client queue-url & {:keys [limit
|
||||
visibility
|
||||
wait-time-seconds
|
||||
^java.util.Collection attributes]
|
||||
:or {limit 1
|
||||
attributes #{}}}]
|
||||
(let [req (-> (ReceiveMessageRequest. queue-url)
|
||||
(.withMaxNumberOfMessages (-> limit (min 10) (max 1) int Integer.))
|
||||
(.withMaxNumberOfMessages (-> limit (min 10) (max 1) int Integer/valueOf))
|
||||
(.withAttributeNames attributes))
|
||||
req (if visibility (.withVisibilityTimeout req (Integer. (int visibility))) req)]
|
||||
req (if wait-time-seconds (.withWaitTimeSeconds req (Integer/valueOf (int wait-time-seconds))) req)
|
||||
req (if visibility (.withVisibilityTimeout req (Integer/valueOf (int visibility))) req)]
|
||||
(->> (.receiveMessage client req)
|
||||
.getMessages
|
||||
(map (partial message-map queue-url)))))
|
||||
|
|
@ -200,4 +215,4 @@
|
|||
;; void removePermission(RemovePermissionRequest removePermissionRequest)
|
||||
; The RemovePermission action revokes any permissions in the queue policy that matches the specified Label parameter.
|
||||
;; void addPermission(AddPermissionRequest addPermissionRequest)
|
||||
;;The AddPermission action adds a permission to a queue for a specific principal.
|
||||
;;The AddPermission action adds a permission to a queue for a specific principal.
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@
|
|||
; sending a msg seems to "force" the queue's existence in listings
|
||||
(send client *test-queue-url* msg)
|
||||
(wait-for-condition #((set (list-queues client)) *test-queue-url*)
|
||||
"Created queue not visible in result of list-queues")))
|
||||
"Created queue not visible in result of list-queues")
|
||||
(wait-for-condition #((set (list-queues client :prefix test-queue-name-prefix)) *test-queue-url*)
|
||||
"Created queue not visible in result of list-queues with prefix")))
|
||||
|
||||
(defsqstest test-queue-attrs
|
||||
(let [{:strs [MaximumMessageSize] :as base-attrs} (queue-attrs client *test-queue-url*)
|
||||
|
|
@ -119,3 +121,11 @@
|
|||
(let [v (-> (receive client *test-queue-url* :visibility 5) first :body read-string)]
|
||||
(is (some #(= v (-> % :body read-string)) (polling-receive client *test-queue-url* :max-wait 10000)))))
|
||||
|
||||
(defsqstest test-receive-long-polling
|
||||
(let [q *test-queue-url*
|
||||
no-poll (future (receive client q))
|
||||
long-poll (future (receive client q :wait-time-seconds 20))]
|
||||
(Thread/sleep 10000)
|
||||
(send client q "1")
|
||||
(is (== 0 (count @no-poll)) "Should not return messages")
|
||||
(is (== 1 (count @long-poll)) "Should return 1 message")))
|
||||
|
|
|
|||
Loading…
Reference in a new issue