Pubsub Ack'd消息每10秒连续重新发送一次(Python beta客户端)

时间:2017-09-23 00:04:01

标签: python google-cloud-pubsub

使用测试版Google Pub / Sub客户端(v0.28.3)

有没有人见过这样一个场景,即每次10分钟都会不断重新传递相同的信息,即使在找到它之后?

这超出了Pub / Sub的至少一次性质。它偶尔会发生,但当它确实发生时,我们会连续几个小时看到相同的消息。

怀疑是因为我们处理来自订阅者的后台线程中的传入消息;但尚未能够始终如一地重现它。那是不是因为某种原因而犹豫不决?

如果是一个错误,很高兴提交它,但假设我们做错了。有没有人处理过类似的问题?

使用调试日志记录,我们可以看到:

D 13:51:46.000 Received response: received_messages { ... message_id: "155264162517414" ... }
D 13:51:46.000 New message received from Pub/Sub: %r
I 13:51:46.000 Processing Message: 155264162517414 
I 13:51:48.000 Acking Message: 155264162517414 
D 13:51:48.000 Sending request: ack_ids: "LDR..."
D 13:51:50.000 Snoozing lease management for 4.009431 seconds. 
D 13:51:50.000 Renewing lease for 0 ack IDs. 
D 13:51:50.000 The current p99 value is 10 seconds. 
...
D 13:51:59.000 Received response: received_messages { ... message_id: "155264162517414" ... }
D 13:51:59.000 New message received from Pub/Sub: %r
I 13:51:59.000 Processing Message: 155264162517414 

这是一个玩具版本的代码,显示了我们如何进行线程化,这有时会触发本地运行的问题:

import Queue
import logging
import threading
import random
import time
from google.cloud import pubsub


SUBSCRIPTION_PATH = ...


class Worker(threading.Thread):
    """Background thread to consume incoming messages."""
    def __init__(self, name):
        threading.Thread.__init__(self, name=name)
        self.queue = Queue.Queue()

    def run(self):
        while True:
            message = self.queue.get()
            self.process(message)
            print '<< Acking :', message.message_id
            message.ack()
            self.queue.task_done()

    def process(self, message):
        """Fake some work by sleeping for 0-15s. """
        s = random.randint(0, 15)
        print '>> Worker sleeping for ', s, message.message_id
        for i in range(s):
            time.sleep(1)
            print i


class Subscriber(threading.Thread):
    """Handles the subscription to pubsub."""
    def __init__(self):
        threading.Thread.__init__(self, name='Subscriber')
        self.subscriber = pubsub.SubscriberClient()
        self.worker = Worker('FakeWorker')
        self.worker.daemon = True

    def run(self):
        self.worker.start()

        flow_control = pubsub.types.FlowControl(max_messages=10)
        policy = self.subscriber.subscribe(SUBSCRIPTION_PATH,
           flow_control=flow_control,
           callback=self._consume)
        print 'Sub started, thread', threading.current_thread()

    def _consume(self, message):
        self.worker.queue.put(message)


if __name__ == '__main__':
    subscriber = Subscriber()
    subscriber.start()
    while 1:
        pass

谢谢!

1 个答案:

答案 0 :(得分:1)

除了Pub / Sub的至少一次性质之外,Pub / Sub中的ack是最好的努力。这意味着ack可以通过两种可能的方式来解决问题&#34;。

  1. 该消息可以由Pub / Sub成功激活,并重新传递一次(可能是由于竞争条件)。
  2. 消息无法成功执行。
  3. 在第二种情况获得的世界中,客户端库不会给你任何类型的错误(因为客户端库本身没有给出),你将开始以节奏的方式看到消息(这将是如果您的处理时间很短,则为10秒。)

    解决此问题的方法是在收到邮件时再次收听邮件。我假设(从玩具代码中不清楚,所以我猜)你只是忽略了重复的消息,但如果你重复一遍,你应该停止获取它。

    如果 重新查找邮件,请open an issue针对客户端库。