使用测试版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
谢谢!
答案 0 :(得分:1)
除了Pub / Sub的至少一次性质之外,Pub / Sub中的ack是最好的努力。这意味着ack可以通过两种可能的方式来解决问题&#34;。
在第二种情况获得的世界中,客户端库不会给你任何类型的错误(因为客户端库本身没有给出),你将开始以节奏的方式看到消息(这将是如果您的处理时间很短,则为10秒。)
解决此问题的方法是在收到邮件时再次收听邮件。我假设(从玩具代码中不清楚,所以我猜)你只是忽略了重复的消息,但如果你重复一遍,你应该停止获取它。
如果 重新查找邮件,请open an issue针对客户端库。