私は、botoを使用してSQSでメッセージを渡すことによってワークフローが管理されるアプリケーションに取り組んでいます。
SQSキューは徐々に大きくなっており、含まれるはずの要素の数を確認する方法がありません。
これで、キューを定期的にポーリングし、固定サイズの要素セットがあるかどうかを確認するデーモンができました。たとえば、次の「キュー」について考えてみます。
q = ["msg1_comp1", "msg2_comp1", "msg1_comp2", "msg3_comp1", "msg2_comp2"]
ここで、ある時点で「msg1_comp1」、「msg2_comp1」、「msg3_comp1」が一緒にキューにあるかどうかを確認したいのですが、キューのサイズがわかりません。
APIを調べたところ、キュー内の要素を1つだけ取得するか、固定数の要素を取得できるようですが、すべてではありません。
>>> rs = q.get_messages()
>>> len(rs)
1
>>> rs = q.get_messages(10)
>>> len(rs)
10
回答で提案されている提案は、たとえば、何も返されないまでループで10個のメッセージを取得することですが、SQSのメッセージには可視性タイムアウトがあります。つまり、キューから要素をポーリングしても、実際には削除されません。それらは短期間しか見えなくなります。
キューにあるすべてのメッセージを、いくつあるかを知らなくても取得する簡単な方法はありますか?
Whileループ内にq.get_messages(n)
を呼び出します。
all_messages=[]
rs=q.get_messages(10)
while len(rs)>0:
all_messages.extend(rs)
rs=q.get_messages(10)
さらに、 ダンプは10を超えるメッセージをサポートしません 次のいずれか:
def dump(self, file_name, page_size=10, vtimeout=10, sep='\n'):
"""Utility function to dump the messages in a queue to a file
NOTE: Page size must be < 10 else SQS errors"""
AWS SQSキューを使用して即時通知を提供しているため、すべてのメッセージをリアルタイムで処理する必要があります。次のコードは、(すべての)メッセージを効率的にデキューし、削除するときにエラーを処理するのに役立ちます。
注:キューからメッセージを削除するには、メッセージを削除する必要があります。更新されたboto3AWS python SDK、jsonライブラリ、および次のデフォルト値を使用しています。
import boto3
import json
region_name = 'us-east-1'
queue_name = 'example-queue-12345'
max_queue_messages = 10
message_bodies = []
aws_access_key_id = '<YOUR AWS ACCESS KEY ID>'
aws_secret_access_key = '<YOUR AWS SECRET ACCESS KEY>'
sqs = boto3.resource('sqs', region_name=region_name,
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key)
queue = sqs.get_queue_by_name(QueueName=queue_name)
while True:
messages_to_delete = []
for message in queue.receive_messages(
MaxNumberOfMessages=max_queue_messages):
# process message body
body = json.loads(message.body)
message_bodies.append(body)
# add message to delete
messages_to_delete.append({
'Id': message.message_id,
'ReceiptHandle': message.receipt_handle
})
# if you don't receive any notifications the
# messages_to_delete list will be empty
if len(messages_to_delete) == 0:
break
# delete messages to remove them from SQS queue
# handle any errors
else:
delete_response = queue.delete_messages(
Entries=messages_to_delete)
私の理解では、SQSサービスの分散性により、設計がほとんど機能しなくなります。 get_messagesを呼び出すたびに、メッセージのすべてではなく一部が含まれる異なるサーバーのセットと通信します。したがって、「時々チェックイン」して特定のメッセージグループの準備ができているかどうかを設定し、それらを受け入れることはできません。
あなたがする必要があるのは、継続的にポーリングし、到着したすべてのメッセージを受け取り、それらを独自のデータ構造にローカルに保存することです。フェッチが成功するたびに、データ構造をチェックして、メッセージの完全なセットが収集されているかどうかを確認できます。
削除はすべてのSQSサーバーに伝播する必要があるため、メッセージwillが順不同で到着し、一部のメッセージwillが2回配信されることに注意してください。削除メッセージを出します。
これをcronジョブで実行します
from Django.core.mail import EmailMessage
from Django.conf import settings
import boto3
import json
sqs = boto3.resource('sqs', aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
region_name=settings.AWS_REGION)
queue = sqs.get_queue_by_name(QueueName='email')
messages = queue.receive_messages(MaxNumberOfMessages=10, WaitTimeSeconds=1)
while len(messages) > 0:
for message in messages:
mail_body = json.loads(message.body)
print("E-mail sent to: %s" % mail_body['to'])
email = EmailMessage(mail_body['subject'], mail_body['message'], to=[mail_body['to']])
email.send()
message.delete()
messages = queue.receive_messages(MaxNumberOfMessages=10, WaitTimeSeconds=1)
以下のコードのようなものでうまくいくはずです。申し訳ありませんが、C#ですが、Pythonに変換するのは難しいことではありません。辞書は、重複を取り除くために使用されます。
public Dictionary<string, Message> GetAllMessages(int pollSeconds)
{
var msgs = new Dictionary<string, Message>();
var end = DateTime.Now.AddSeconds(pollSeconds);
while (DateTime.Now <= end)
{
var request = new ReceiveMessageRequest(Url);
request.MaxNumberOfMessages = 10;
var response = GetClient().ReceiveMessage(request);
foreach (var msg in response.Messages)
{
if (!msgs.ContainsKey(msg.MessageId))
{
msgs.Add(msg.MessageId, msg);
}
}
}
return msgs;
}