如何使用python

时间:2019-04-30 14:51:29

标签: python google-cloud-platform google-cloud-functions google-cloud-pubsub

我正在设置一个新的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文件夹,并确保不向该文件夹添加任何触发器。


2 个答案:

答案 0 :(得分:1)

通常,Google Cloud Pub / Sub保证at least once delivery消息。这意味着总是有可能获得副本,尽管它们应该相对较少。在您的情况下,并不是同一条消息被一遍又一遍地处理,而是不同的消息。诸如518626734652287之类的数字是消息ID。由于这些每次都不同,因此意味着发布了多个消息。可能正在发生以下两种情况之一:

  1. 文件多次上传。
  2. GCS触发器已设置多次。您可以通过运行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()