我正在设置一个新的GCP项目,以便在将CSV文件上传到存储桶后立即对其进行读取和解析。在这种程度上,我创建了一个发布到发布/订阅的触发器。 Pub / Sub本身会将消息发送到后台功能。
一切似乎都正常,例如文件上传后,触发器立即生效,可以将消息发送到Pubsub,然后发送给该函数。我还可以看到该功能的消息。
但是,问题是将Ack发送回发布/订阅。我在某个地方读到发回任何2xx状态应该可以完成此工作(从队列中删除消息),但事实并非如此。结果pubsub“认为”该消息尚未传递,并反复发送该消息。
def parse_data(data, context):
if 'data' in data:
args = base64.b64decode(data['data']).decode('utf-8')
pubsub_message = args.replace('\n', ' ')
properties = json.loads(pubsub_message)
myBucket = validate_message(properties, 'bucket')
myFileName = validate_message(properties, "name")
fileLocation = 'gs://'+myBucket+'/'+myFileName
readAndEnhanceData(fileLocation)
return 'OK', 200
else:
return 'Something went wrong, no data received'
这是显示该函数被连续调用的日志文件。
D CSV_Parser_Raw_Data 518626734652287 Function execution took 72855 ms,
finished with status: 'ok' CSV_Parser_Raw_Data 518626734652287
D CSV_Parser_Raw_Data 518626708442766 Function execution took 131886 ms,
finished with status: 'ok' CSV_Parser_Raw_Data 518626708442766
D CSV_Parser_Raw_Data 518624470100006 Function execution took 65412 ms,
finished with status: 'ok' CSV_Parser_Raw_Data 518624470100006
D CSV_Parser_Raw_Data 518626734629237 Function execution took 68004 ms,
finished with status: 'ok' CSV_Parser_Raw_Data 518626734629237
D CSV_Parser_Raw_Data 518623777839079 Function execution took 131255 ms,
finished with status: 'ok' CSV_Parser_Raw_Data 518623777839079
D CSV_Parser_Raw_Data 518623548622842 Function execution took 131186 ms,
finished with status: 'ok' CSV_Parser_Raw_Data 518623548622842
D CSV_Parser_Raw_Data 518623769252453 Function execution took 133981 ms,
finished with status: 'ok' CSV_Parser_Raw_Data 518623769252453
因此,我很高兴知道我在这里缺少什么!即我该如何打破这个循环?
*关于此问题的更新* 感谢@kamal,他强迫我睁开眼睛,责成自己重新创建存储桶/主题等。在我执行任务时,重新查看了所有内容并意识到,我在子文件夹中使用了一个临时文件,但在SAME存储桶中作为上传文件!这就是问题所在。 完成事件适用于存储桶中任何在任何地方创建的对象。因此,Kamal是对的,正在进行多次上传!
如果您以相同的方式处理项目,请确保创建一个tmp文件夹,并确保不向该文件夹添加任何触发器。
答案 0 :(得分:1)
通常,Google Cloud Pub / Sub保证at least once delivery消息。这意味着总是有可能获得副本,尽管它们应该相对较少。在您的情况下,并不是同一条消息被一遍又一遍地处理,而是不同的消息。诸如518626734652287之类的数字是消息ID。由于这些每次都不同,因此意味着发布了多个消息。可能正在发生以下两种情况之一:
gsutil notification list gs://<bucket name>
进行检查。如果是后者的问题,您将看到多个条目,例如:
projects/_/buckets/my-bucket/notificationConfigs/1
Cloud Pub/Sub topic: projects/cloud-pubsub-training-examples/topics/my-topic
projects/_/buckets/my-bucket/notificationConfigs/2
Cloud Pub/Sub topic: projects/cloud-pubsub-training-examples/topics/my-topic
projects/_/buckets/my-bucket/notificationConfigs/3
Cloud Pub/Sub topic: projects/cloud-pubsub-training-examples/topics/my-topic
您可以通过发出带有配置名称(例如gsutil notification delete projects/_/buckets/my-bucket/notificationConfigs/2
)的删除来删除多余的通知。
还值得注意的是,使用Cloud Functions和Pub / Sub,可以设置两种类型的订阅:用户配置的订阅和Cloud Functions本身配置的订阅。缺省情况下,前者的ack截止时间为10秒。这意味着,如果在10秒钟内未确认消息,则将重新发送该消息。对于后者,默认值为600秒。如果邮件处理时间超过此时间段,则很有可能会重新发送邮件。
您可以尝试减少处理邮件所需的时间,也可以增加确认期限。您可以使用gcloud
工具来延长确认期限:
gcloud pubsub subscriptions update <subscription name> --ack-deadline=180
这会将截止日期延长至3分钟。您也可以在Cloud Console Pub/Sub page中进行此操作,方法是:单击订阅,单击“编辑”,然后将“确认截止日期”更改为较大的值。
使用Cloud Functions,您无需返回HTTP状态。仅当您直接使用push subscription时才需要这样做。
答案 1 :(得分:0)
您不能只从函数中返回200。您实际上需要“确认” pubsub消息。您尚未显示实际从pubsub获取消息的代码,但我认为该代码中的某处具有以下内容:
queue = Queue.Queue()
message = queue.get()
parse_data(message.data, context)
那是您需要确认消息的地方:
queue = Queue.Queue()
message = queue.get()
if parse_data(message.data, context):
message.ack()