Python 3.x GCP消息在确认后保留在发布/订阅中

Python 3.x GCP消息在确认后保留在发布/订阅中,python-3.x,google-cloud-platform,publish-subscribe,google-cloud-pubsub,Python 3.x,Google Cloud Platform,Publish Subscribe,Google Cloud Pubsub,我将发布/订阅逻辑包装在subscribe方法中,该方法在每个订阅的服务初始化期间被调用一次: def订阅(self、, callback:typing.Callable, 订阅名称:str, 主题名称:str, 项目名称:str=None)->键入。可选[SubscriberClient]: “”“订阅发布/子主题并返回订阅服务器客户端” :param callback:订阅回调方法 :param subscription\u name:订阅的名称 :param topic_name:主题的名

我将发布/订阅逻辑包装在subscribe方法中,该方法在每个订阅的服务初始化期间被调用一次:

def订阅(self、,
callback:typing.Callable,
订阅名称:str,
主题名称:str,
项目名称:str=None)->键入。可选[SubscriberClient]:
“”“订阅发布/子主题并返回订阅服务器客户端”
:param callback:订阅回调方法
:param subscription\u name:订阅的名称
:param topic_name:主题的名称
:param project_name:可选项目名称。如果未设置,则使用默认项目
:return:订阅服务器客户端或无(如果正在测试)
"""
项目=项目名称如果项目名称else self.pubsub项目id
self.logger.info('订阅项目`{}`,主题`{}`。格式(项目,主题名称))
project\u path=self.pubsub\u订户.project\u路径(project)
主题路径=self.pubsub\u订户.topic\u路径(项目,主题名称)
订阅路径=self.pubsub\u订阅方.subscription\u路径(项目,订阅名称)
#检查是否存在现有订阅,如果没有,请创建它
如果订阅路径不在[s.name for s in self.pubsub\u subscriber.list\u订阅(项目路径)]:
self.logger.info('创建新订阅`{}`,主题`{}`'。格式(订阅名称,主题名称))
self.pubsub\u subscriber.create\u订阅(订阅路径、主题路径)
#订阅该主题
self.pubsub_subscriber.subscribe(
订阅路径,回调=回调,
调度程序=self.thread\u调度程序
)
返回self.pubsub_订户
此方法的调用方式如下:

self.subscribe\u client=self.subscribe(
回调=self.pubsub\u回调,
订阅名称=“订阅主题”,
topic_name='topic'
)
回调方法会做很多事情,发送两封电子邮件,然后确认消息

def pubsub_回调(self,data:gcloud_pubsub_subscriber.Message):
self.logger.debug('正在处理发布子消息')
尝试:
self.do\u某事\u与\u消息(数据)
self.logger.debug('确认消息')
data.ack()
self.logger.debug('已确认')
返回
除:
自我警告({
“消息”:“未能处理发布/订阅消息”,
“请求大小”:data.size,
“数据”:data.data
},exc_info=True)
self.logger.debug('确认消息2')
data.ack()
当我运行push something to the subscription时,callback运行并打印所有调试消息,包括
Acknowledged
。但是,消息会留在Pub/Sub中,回调会再次被调用,每次重试后都会花费指数时间。问题是,即使在调用了
ack
之后,是什么会导致消息留在发布/订阅中

我有几个这样的订阅,所有的都按预期工作。最后期限不是一个选项,回调几乎立即结束,我玩了ack的最后期限,没有任何帮助

当我尝试从连接到该发布订阅的本地运行的应用程序处理这些消息时,它会很好地完成,并且acknowledge会按预期将消息从队列中取出

  • 因此,问题只表现在部署的服务中(在kubernetes吊舱中运行)
  • 回调执行buck ack似乎什么都不做
  • 从本地运行的脚本(并执行完全相同的操作)或通过GCP UI确认消息的工作与预期的一样

有什么想法吗?

在发布/订阅中,致谢是最好的办法,因此,重新发送邮件是可能的,但并不常见

如果您一直收到重复的消息,可能是由于相同消息内容的重复发布。就发布/订阅而言,这些是不同的消息,将分配不同的消息ID。检查发布/订阅提供的消息ID,确保您多次实际收到同一消息

有(这是Python客户机库使用的)。如果在同一订阅上运行多个客户端订阅,则此边缘情况可能相关

您还可以检查订阅以查看:

  • 如果其确认被成功发送(
    subscription/ack\u message\u count
  • 如果其积压正在减少(
    订阅/backlog\u字节
  • 如果您的订户错过确认截止日期(
    subscription/streaming\u pull\u ack\u message\u operation\u count
    通过
    response\u code!=“success”
    过滤)

如果您没有错过ack截止日期,并且您的积压工作保持稳定,那么您应该与Google云支持部门联系,并提供项目名称、订阅名称和重复消息ID的示例。他们将能够调查这些重复发生的原因。

我做了一些额外的测试,最终发现了问题

TL;DR:我对所有订阅使用了相同的
google.cloud.pubsub\u v1.subscriber.scheduler.ThreadScheduler

下面是我用来测试它的代码片段。这是损坏的版本:

server.py

import concurrent.futures.thread
导入操作系统
导入时间
从google.api_core.exceptions导入AlreadyExists
从google.cloud导入pubsub_v1
从google.cloud.pubsub_v1.subscriber.scheduler导入ThreadScheduler
def创建订阅(项目id、主题名称、订阅名称):
“”“在给定主题上创建新的请求订阅。”“”
subscriber=pubsub_v1.SubscriberClient()
主题路径=订阅者。主题路径(项目id、主题名称)
订阅路径=订阅