I’m looking at the docs for https://hexdocs.pm/aws/AWS.SQS.html#send_message_batch/3
send_message_batch(client, input, options \\ [])
but it’s not clear what the input
parameter is. Looking at the aws sdk docs for javascript and golang, I’m inferring that input
is something like this in elixir:
input = %{
"Entries" => batch, #list,
"QueueUrl" => "..." #string
}
Where the Entries
key should probably be something like a list of maps like this:
batch = [%{
"Id" => id,
"MessageBody" => message_body,
"MessageDeduplicationId" => group_id,
"MessageGroupId" => group_id
}]
The problem is, when I call:
AWS.SQS.send_message_batch(client, input)
I get the error:
** (ArgumentError) cannot convert the given list to a string.
To be converted to a string, a list must either be empty or only
contain the following elements:
* strings
* integers representing Unicode code points
* a list containing one of these three elements
Is this a bug or am I doing something wrong?
It seems as though “Entries” can’t be a list of maps, but I don’t know what else to give it.
The generated code is a really thin wrapper over the underlying API. First thing to notice is how the values in input
get encoded for a :query
format:
This expects a map with a single level of keys & values, no nesting.
AWS appears to want a special format with .N
s embedded in the field names:
https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue/
?Action=SendMessageBatch
&SendMessageBatchRequestEntry.1.Id=test_msg_001
&SendMessageBatchRequestEntry.1.MessageBody=test%20message%20body%201
&SendMessageBatchRequestEntry.2.Id=test_msg_002
&SendMessageBatchRequestEntry.2.MessageBody=test%20message%20body%202
&SendMessageBatchRequestEntry.2.DelaySeconds=60
&SendMessageBatchRequestEntry.2.MessageAttribute.1.Name=test_attribute_name_1
&SendMessageBatchRequestEntry.2.MessageAttribute.1.Value.StringValue=test_attribute_value_1
&SendMessageBatchRequestEntry.2.MessageAttribute.1.Value.DataType=String
&Expires=2020-05-05T22%3A52%3A43PST
&Version=2012-11-05
&AUTHPARAMS
(from the docs)
Hi @homanchou
input
is a list of keywords (but I guess maps would also work) having at least these elements:
[
id: String.t(),
message_body: String.t()
]
So make sure you convert your message body to a string, for example using JSON.
See: SendMessageBatchRequestEntry - Amazon Simple Queue Service
This is what my code looks like:
def send_messages(queue, messages) when is_binary(queue) and is_list(messages) do
messages =
for {message, id} <- Enum.with_index(messages),
do: [id: id, message_body: Jason.encode!(message)]
messages
|> Enum.chunk_every(@sqs_max_batch_size)
|> Enum.reduce_while({:ok, 0}, fn batch, {:ok, sent_so_far} ->
case send_batch(queue, batch) do
{:ok, sent} -> {:cont, {:ok, sent_so_far + sent}}
error -> {:halt, error}
end
end)
end
defp send_batch(queue, messages) do
case ExAws.SQS.send_message_batch(queue, messages) |> ExAws.request() do
{:ok, %{body: %{failures: [], successes: successes}}} when is_list(successes) ->
{:ok, length(successes)}
{:ok, %{body: %{failures: failures}}} ->
{:error, %{failures: failures}}
error ->
error
end
end
As you can see, I’m using an integer as message id and that also works.
Hope this can help.