-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make aws client selectable #16
Changes from 16 commits
f1538fc
d6c1b2e
884de2d
8f6285d
ae3d586
3955f44
0504b09
2c75142
0bfdbdf
7ab1949
f91c752
a7ea267
fd52ff5
ce32fb9
2a3109c
87c1b7c
bac640b
16df045
027d383
e95b8cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
(ns gluttony.core | ||
(:require | ||
[cognitect.aws.client.api :as aws] | ||
[gluttony.protocols :as p] | ||
[gluttony.record.consumer :as c]) | ||
(:import | ||
|
@@ -37,10 +36,9 @@ | |
(if success? | ||
(respond) | ||
(raise 10)))) | ||
client - An instance of gluttony.protocols/ISqsClient. | ||
|
||
Optional arguments: | ||
:client - the SQS client, which is the instance of cognitect.aws.client.Client. | ||
if missing, cognitect.aws.client.api/client would be called. | ||
:num-workers - the number of workers processing messages concurrently. | ||
default: (Runtime/availableProcessors) - 1 | ||
:num-receivers - the number of receivers polling from sqs. | ||
|
@@ -81,11 +79,8 @@ | |
:visibility-timeout-in-heartbeat must be longer than :heartbeat. | ||
Output: | ||
a instance of gluttony.record.consumer.Consumer" | ||
^Consumer [queue-url consume & [opts]] | ||
(let [client (or (:client opts) | ||
(aws/client {:api :sqs})) | ||
given-client? (some? (:client opts)) | ||
num-workers (or (:num-workers opts) | ||
^Consumer [queue-url consume client & [opts]] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to add an assertion for the client here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Other type checks are done within There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't notice that. No action is needed then. |
||
(let [num-workers (or (:num-workers opts) | ||
(max 1 (dec (.availableProcessors (Runtime/getRuntime))))) | ||
num-receivers (or (:num-receivers opts) | ||
(max 1 (int (/ num-workers 10)))) | ||
|
@@ -105,7 +100,6 @@ | |
consumer (c/new-consumer {:queue-url queue-url | ||
:consume consume | ||
:client client | ||
:given-client? given-client? | ||
:num-workers num-workers | ||
:num-receivers num-receivers | ||
:message-channel-size message-channel-size | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
(ns gluttony.record.aws-sqs-client | ||
(:require | ||
[clojure.core.async :as as] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT In another namespace, |
||
[gluttony.protocols :as p]) | ||
(:import | ||
(java.util.function | ||
BiConsumer) | ||
(software.amazon.awssdk.services.sqs | ||
SqsAsyncClient) | ||
(software.amazon.awssdk.services.sqs.model | ||
ChangeMessageVisibilityRequest | ||
DeleteMessageRequest | ||
Message | ||
MessageSystemAttributeName | ||
ReceiveMessageRequest | ||
ReceiveMessageResponse))) | ||
|
||
(defrecord AwsSqsClient [^SqsAsyncClient client | ||
given-client?] | ||
p/ISqsClient | ||
(receive-message [_ {:keys [queue-url | ||
max-number-of-messages | ||
wait-time-seconds]}] | ||
(let [chan (as/chan 1) | ||
request (-> (ReceiveMessageRequest/builder) | ||
(.queueUrl queue-url) | ||
(.messageAttributeNames ["All"]) | ||
(.messageSystemAttributeNames [MessageSystemAttributeName/ALL]) | ||
(.maxNumberOfMessages (int max-number-of-messages)) | ||
(.waitTimeSeconds (int wait-time-seconds)) | ||
(.build))] | ||
(-> (.receiveMessage client request) | ||
(.whenComplete (reify BiConsumer | ||
(accept [_ message-resp error] | ||
(as/>!! chan (if message-resp | ||
{:messages (vec (.messages ^ReceiveMessageResponse message-resp)) | ||
:error nil} | ||
{:message nil :error error})) | ||
(as/close! chan))))) | ||
chan)) | ||
(delete-message [_ {:keys [queue-url receipt-handle]}] | ||
(let [chan (as/chan 1) | ||
request (-> (DeleteMessageRequest/builder) | ||
(.queueUrl queue-url) | ||
(.receiptHandle receipt-handle) | ||
(.build))] | ||
(-> (.deleteMessage client request) | ||
(.whenComplete (reify BiConsumer | ||
(accept [_ _ error] | ||
(as/>!! chan {:error error}) | ||
(as/close! chan))))) | ||
chan)) | ||
(change-message-visibility [_ {:keys [queue-url receipt-handle visibility-timeout]}] | ||
(let [chan (as/chan 1) | ||
request (-> (ChangeMessageVisibilityRequest/builder) | ||
(.queueUrl queue-url) | ||
(.receiptHandle receipt-handle) | ||
(.visibilityTimeout (int visibility-timeout)) | ||
(.build))] | ||
(-> (.changeMessageVisibility client request) | ||
(.whenComplete (reify BiConsumer | ||
(accept [_ _ error] | ||
(as/>!! chan {:error error}) | ||
(as/close! chan))))) | ||
chan)) | ||
(get-message-id [_ message] | ||
(.messageId ^Message message)) | ||
(get-recipient-handle [_ message] | ||
(.receiptHandle ^Message message)) | ||
(stop [_] | ||
(when-not given-client? | ||
(.close client)))) | ||
|
||
|
||
(defn make-client | ||
([] | ||
(make-client nil)) | ||
([api-client] | ||
{:pre [(or (instance? SqsAsyncClient api-client) | ||
(nil? api-client))]} | ||
(->AwsSqsClient (or api-client | ||
(SqsAsyncClient/create)) | ||
(some? api-client)))) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
(ns gluttony.record.cognitect-sqs-client | ||
(:require | ||
[camel-snake-kebab.core :as csk] | ||
[camel-snake-kebab.extras :as cske] | ||
[clojure.core.async :as a] | ||
[cognitect.aws.client.api :as aws] | ||
[gluttony.protocols :as p]) | ||
(:import | ||
(cognitect.aws.client.impl | ||
Client))) | ||
|
||
(defn- invoke-async | ||
[client op-map] | ||
(let [op-map (update op-map :request #(cske/transform-keys csk/->PascalCaseKeyword %))] | ||
(a/go | ||
(when-let [res (a/<! (aws/invoke-async client op-map))] | ||
(cske/transform-keys csk/->kebab-case-keyword res))))) | ||
|
||
(defrecord CognitectSQSClient | ||
;; AWS SQS client implementation using cognitect.aws.client.api | ||
;; The structure of Output of functions are same as `(:response (:ReceiveMessage (aws/ops client)))`, | ||
;; but the keys are kebab-case-keyword. | ||
[client given-client?] | ||
p/ISqsClient | ||
(receive-message [_ request] | ||
(a/go | ||
(let [request (merge {:message-attribute-names ["All"] | ||
:message-system-attribute-names ["All"]} | ||
request) | ||
response (a/<! (invoke-async client {:op :ReceiveMessage :request request}))] | ||
(if (contains? response :category) | ||
{:messages nil :error response} | ||
{:messages (:messages response) :error nil})))) | ||
(delete-message [_ request] | ||
(a/go | ||
(let [response (a/<! (invoke-async client {:op :DeleteMessage :request request}))] | ||
{:error (when (contains? response :category) | ||
response)}))) | ||
(change-message-visibility [_ request] | ||
(a/go | ||
(let [response (a/<! (invoke-async client {:op :ChangeMessageVisibility :request request}))] | ||
{:error (when (contains? response :category) | ||
response)}))) | ||
(get-message-id [_ message] | ||
(:message-id message)) | ||
(get-recipient-handle [_ message] | ||
(:receipt-handle message)) | ||
(stop [_] | ||
(when-not given-client? | ||
(aws/stop client)))) | ||
|
||
(defn make-client | ||
([] | ||
(make-client nil)) | ||
([api-client] | ||
{:pre [(or (instance? Client api-client) | ||
(nil? api-client))]} | ||
(->CognitectSQSClient (or api-client | ||
(aws/client {:api :sqs})) | ||
(some? api-client)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add
:licenses
?https://github.com/liquidz/build.edn/blob/main/doc/format/licenses.adoc
Now clojars requires that pom.xml contains license information.
clojars/clojars-web#874