我有一个在Elastic Beanstalk上运行的worker,它通过队列中的消息接受POST请求。这些消息会触发长时间操作,这需要几分钟(有时甚至几小时),并且此操作仅执行一次至关重要。
问题在于,当我登录到工作人员控制台查看进程时,消息似乎每隔一分钟一遍又一遍地传递(通过接收请求触发的方法每分钟调用一次)。我怎样才能摆脱这种行为?
我阅读了文档,并将可见超时期间设置为服务队列和死信队列的最大值(12小时)。然而,这确实没有任何帮助。
当我发送消息时,它显示为“在飞行中”(这是一种假设的行为,我认为,因为队列等待接收删除请求或某种答案,仅在结束时提供长期运作)。
有人会暗示我在这种情况下发生了什么吗?我可能错过了配置中的一些重要细节......
编辑:只要它在“飞行中”,似乎每分钟都会重新传递消息。完成此过程后,消息最终消失。答案 0 :(得分:5)
似乎您忘记在处理后删除邮件。
将消息出列后,必须将其删除。如果您没有明确删除它,SQS会假定您将消息出列并且无法处理它,因此它将再次出现在队列中。
您可以在SQS中设置2个超时参数,这两个参数都很重要:
WaitTimeSeconds
VisibilityTimeout
1)WaitTimeSeconds = 10
表示如果队列中有消息,您对SQS的调用应立即返回,但如果队列中没有消息,您的呼叫将阻塞,直到消息到达队列,最多10秒。
2)消息出列后,VisibilityTimeout = 60
表示您有60秒处理该消息,否则它将再次出现在队列中。如果您在60秒之前处理了该消息,则必须发送deleteMessage
请求。如果您在60秒之前未能发送deleteMessage
请求,则该消息将重新出现在队列中。
如果您在60秒后发送deleteMessage
请求,它将无效,并且无论如何都会重新显示该消息。
您必须以一种方式编写代码,如果您的流程失败,它自然会无法发送deleteMessage
请求,因此该消息将自然地再次出现在SQS中。
您可以在此处找到有关1)和2)的详细信息:
http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/MessageLifecycle.html
http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-long-polling.html
http://boto.readthedocs.org/en/latest/ref/sqs.html#boto.sqs.queue.Queue.get_messages
答案 1 :(得分:4)
这里有一层额外的复杂性,因为你没有直接轮询SQS队列; Elastic Beanstalk部署了一个名为sqsd
的工作进程,它代表您轮询队列,将其获取的任何消息发布到您的应用程序,并在您使用200响应时将其从队列中删除。
队列上的VisibilityTimeout设置控制队列在将消息传递给使用者(在本例中为sqsd)之后等待多长时间,然后才会出现错误并将消息重新传递给其他人。 sqsd有一个类似的概念(称为“InactivityTimeout”),它控制 it 在POST到应用程序之后等待多长时间才会出现错误并重试之前。您需要将其配置为足够高,以便sqsd在您完成处理之前不会将请求重新发送到您的应用程序。我看过另一个“ProxyTimeout”设置的reports,也可能需要调整。
更一般地说,请记住exactly-once delivery在物理上不可能在分布式系统中保证 - 即使你得到了所有的超时权限,所以它在大多数情况下都能正常工作,总有可能你完成操作后会崩溃,但在您告诉SQS之前,该消息将重新发送给其他人。您可以获得的最接近的是确保如果消息被传递两次,结果完全相同 - 例如,让您的处理逻辑检查它将要做的事情是否已经已经完成,如果是这样,只需立即返回200。
答案 2 :(得分:1)
使用sqs,您必须手动调用delete api以从队列中删除消息。 设置高超时值只能确保没有其他轮询器在该时间内收到相同的消息。
您有2个选项。 1.读取后立即删除该消息,然后启动下游过程。 2.阅读消息,将消息的可见性超时设置为进程的超时值,然后作为进程的一部分,最后一步是删除消息。