我知道SQS不是为此而构建的,但我很好奇是否可以在符合某些条件的队列中查找消息?
我可以在循环中提取消息,在消息正文中搜索某些模式(甚至不反序列化它们),并过滤我需要的消息。但是有可能最终得到一个无限循环 - 我读到的第一个消息将在我到达队列末尾时返回队列...
扩展可能的消息可见性,但我如何确切地知道扫描整个队列需要多长时间,以及我应该延长可见性的时间长度?如果我在那里有一万条消息怎么办?
这里有解决方法吗? 我需要扫描队列中的某些消息,然后删除那些消息......
答案 0 :(得分:15)
简答:不。
队列专为任务而设计。机器从队列中获取新任务(即消息),执行任务,然后删除任务。
如果您正在尝试搜索邮件以过滤它们,我不禁想知道您是否使用了错误的工具...
答案 1 :(得分:3)
我不认为短或长的答案是"否"。
以下两个对位解决方案是"是"。
<强> 1。遍历队列,维护访问列表
考虑具有N
消息的队列的情况,不添加或删除消息。如果没有其他信息(例如,如果您知道有多少邮件符合您的条件),则需要遍历所有N
条消息。
这里的关键点是知道您何时浏览了所有N
条消息。这里有一些问题。
ApproximateNumberOfMessages
属性要维护受访列表,当您收到消息并评估匹配条件时,您可以存储所有已访问消息的message_id
。
消息ID 几乎唯一。见这个帖子
https://forums.aws.amazon.com/message.jspa?messageID=76119
如果你选择了(3),你就不能确定需要多少次迭代才能耗尽队列。但是,如果您无限期地执行此操作,只要SQS分片服务器上的加权随机分布为其提供所有非零概率,您就可以保证排除队列。
<强> 2。使用企业集成模式(邮件路由)根据条件将邮件拆分为下游
如果您可以控制您的消息传递体系结构,则可以使用消息路由器作为&#34;前端&#34;消息处理器根据条件将消息分派给各个收件人。
特别是您使用基于内容的路由器:
http://www.enterpriseintegrationpatterns.com/patterns/messaging/ContentBasedRouter.html
答案 2 :(得分:2)
我们有一个类似的要求,最终得到了本“动手实践”教程中描述的体系结构:Filter Messages Published to Topics。
从本质上讲,您无需将事件/消息发布到SQS队列中,而是将它们发布到SNS主题,并且每个使用者都将拥有自己的订阅该主题的SQS队列。然后,您可以使用SNS Subscription Filters来确保仅将相关消息排队到每个使用者的队列中。
这会增加基础架构的开销,但它可以很好地为我们提供解决方案。
答案 3 :(得分:0)
使用不同的案例进行测试。这是行不通的。答案是否
<强> TESTDATA 强>
public void fillQueueWithMessages(){
MessageAttributeValue value1 = new MessageAttributeValue();
value1.setDataType("String");
value1.setStringValue("1");
SendMessageRequest send_msg_request = new SendMessageRequest()
.withQueueUrl(env.getProperty("cloud.aws.sqs.readyForTranslation.url"))
.withMessageBody("test1").addMessageAttributesEntry(value1.getStringValue(), value1);
amazonSqs.sendMessage(send_msg_request);
MessageAttributeValue value2 = new MessageAttributeValue();
value2.setDataType("String");
value2.setStringValue("2");
SendMessageRequest send_msg_request2 = new SendMessageRequest()
.withQueueUrl(env.getProperty("cloud.aws.sqs.readyForTranslation.url"))
.withMessageBody("test2").addMessageAttributesEntry(value2.getStringValue(), value2);
amazonSqs.sendMessage(send_msg_request2);
SendMessageRequest send_msg_request3 = new SendMessageRequest()
.withQueueUrl(env.getProperty("cloud.aws.sqs.readyForTranslation.url"))
.withMessageBody("test3").addMessageAttributesEntry(value1.getStringValue(), value1);
amazonSqs.sendMessage(send_msg_request3);
}
<强>测试强>
public void shouldPollMessagesBasedOnMessageAttribute() throws InterruptedException {
ReceiveMessageRequest request =
new ReceiveMessageRequest(env.getProperty("cloud.aws.sqs.readyForTranslation.url"));
request.setMaxNumberOfMessages(3);
request.setWaitTimeSeconds(20);
request.withMessageAttributeNames("1");
List<Message> messages = new ArrayList<Message>();
messages = amazonSqs.receiveMessage(request).getMessages();
assertEquals(2, messages.size());
}
答案 4 :(得分:0)
对于谦虚的devops工程师来说,它可以完全控制所有事情:
(1)快速关闭使用者,以便将消息捕获到队列中。
(2)关闭信号源。
(3)阅读所有SQS队列以查找您的消息,同时还将其复制到“临时”队列中。
(4)将所有“ temp”队列复制回SQS队列。 Google它有很多工具。
(5)重新启动源和使用者。
如果您事先想到了另一种方法,则可以使用SNS或其他东西将其复制到辅助“ devops”队列中,并在需要查找消息时通读它。您可以将“ devops”队列的保留期设置为较短,以使其大小合理。
答案 5 :(得分:0)
好,这个问题永远存在很久,所以doron-BGU bgu声称属性如他所描述的那样起作用。
我有几个“生产者”将相同的JSON发送到我的SQS中,我的“消费者”必须根据他们的来源,移动客户端,MVC客户端或其他台式应用程序与他们跳舞,而不同。 / p>
我很想测试doron-BGU bgu的理论真的很糟糕。但务实的是,我的单个使用者对队列中的这些消息执行了截然不同的处理,只是检查了每个消息中的JSON中的值,我迫使生产者在其中定义了消息的来源。苹果在那儿去了橘子。
答案 6 :(得分:0)
旧主题,但可能会有所帮助 您可以将FIFO与GroupId一起使用以获取少量消息 thread which helped me
答案 7 :(得分:-1)
通过一些例子让我们理解这一点 所以创建10条消息并发送
// Send a message
for (int i = 0; i < 10; i++) {
System.out.println("Sending a message to MyQueue.\n");
Map<String, MessageAttributeValue> messageAttributes = new HashMap<>();
// extra code
String sdate;
Format formatter;
Date date = new Date();
// 2012-12-01
formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
sdate = formatter.format(date);
System.out.println(sdate);
messageAttributes.put("Datestamp"+i, new MessageAttributeValue().withDataType("String").withStringValue(sdate));
Map<String, MessageAttributeValue> messageAttributes1 = new HashMap<>();
messageAttributes1.put("attributeName", new MessageAttributeValue().withDataType("String").withStringValue(sdate));
SendMessageRequest request = new SendMessageRequest();
request.withMessageBody("A test message body."+sdate);
request.withQueueUrl(myQueueUrl);
request.withMessageAttributes(messageAttributes);
sqs.sendMessage(request);
}
现在,即使您有10条消息,其中datetimestamp1到datetimestamp10
使用属性过滤不起作用
让我们尝试过滤一些myTag属性
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);
//ReceiveMessageRequest receiveRequest = new ReceiveMessageRequest(queueUrl);
receiveMessageRequest.withMaxNumberOfMessages(10);
receiveMessageRequest.withMessageAttributeNames("myTag");
List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
它提供10条消息,myTag值为空
message.getMessageAttributes()。get(&#34; Datestamp&#34;)为null message.getMessageAttributes()。get(&#34; myTag&#34;)为null
因此我们无法使用message属性进行过滤,就好像找不到该键一样。 没有消息属性或所有消息属性都相同。
如此长的答案是NOOOOO
答案 8 :(得分:-4)
这实际上并非都是如此,
实际上你可以'有点'使用消息属性技巧来过滤队列中的消息。
每条消息都可以包含您在创建消息时可以添加的属性(您需要为每个属性提供3项内容:名称,类型,值)。
稍后,当你创建新的ReceiveMessageRequest对象时,你可以使用“withMessageAttributeNames”来指定一个属性,实际发生的是你的队列被过滤掉包含该特定属性的messaged。
例如:
String queueUrl = sqs.getQueueUrl("myQueue").getQueueUrl();
ReceiveMessageRequest receiveRequest = new ReceiveMessageRequest(queueUrl);
receiveRequest.withMaxNumberOfMessages(10);
receiveRequest.withMessageAttributeNames("myTag");
如果您的队列中有5条消息,但只有1条消息具有“myTag”属性,则只返回该特定的消息。
对我来说这是压倒性的,因为ReceiveMessageRequest API
中没有提到这一点所以基本上你所要做的就是给每条消息一个独特的属性(请注意属性限制:The message attribute name can contain the following characters: A-Z, a-z, 0-9, underscore (_), hyphen (-), and period (.). The name must not start or end with a period, and it should not have successive periods. The name is case sensitive and must be unique among all attribute names for the message. The name can be up to 256 characters long. The name cannot start with "AWS." or "Amazon." (or any variations in casing)