GCP Cloud Tasks:缩短创建先前创建的命名任务的时间

Posted

技术标签:

【中文标题】GCP Cloud Tasks:缩短创建先前创建的命名任务的时间【英文标题】:GCP Cloud Tasks: shorten period for creating a previously created named task 【发布时间】:2020-12-20 23:21:20 【问题描述】:

我们正在开发一个基于 GCP Cloud Task 的队列进程,该进程会在特定 Firestore 文档写入触发器触发时发送状态电子邮件。我们使用 Cloud Tasks 的原因是可以在发送电子邮件之前创建延迟(在未来使用 scheduleTime 属性 2 分钟),并控制重复数据删除(通过使用格式化为的任务名称:[firestore-collection-name ]-[doc-id]),因为在创建文档时可以多次触发 Firestore 文档上的“写入”触发器,然后由后端云功能快速更新。

一旦达到任务的延迟期,云任务就会运行,并发送包含更新的 Firestore 文档信息的电子邮件。之后任务从队列中删除,一切正常。

除了:

如果用户更新 Firestore 文档(比如 20 或 30 分钟后),我们希望重新发送状态电子邮件,但无法使用相同的任务名称创建任务。我们得到以下错误:

409 The task cannot be created because a task with this name existed too recently. For more information about task de-duplication see https://cloud.google.com/tasks/docs/reference/rest/v2/projects.locations.queues.tasks/create#body.request_body.FIELDS.task.

这是出乎意料的,因为此时队列为空,因为最后一个任务已成功完成。错误消息中引用的文档说:

如果任务的队列是使用 Cloud Tasks 创建的,则另一个任务 在原始任务后约 1 小时内无法创建同名 被删除或执行。

问题:有没有什么方法可以通过减少时间来绕过这个限制,甚至一起取消限制?

【问题讨论】:

【参考方案1】:

简短的回答是否定的。正如您已经指出的那样,文档对这种行为非常清楚,您应该等待 1 小时来创建与之前创建的同名的任务。 API 或客户端库不允许减少此时间。

话虽如此,我建议不要使用相同的任务 ID,而是为任务使用不同的 ID,并在请求的正文中添加一个标识符。例如,使用 Python:

from google.cloud import tasks_v2
from google.protobuf import timestamp_pb2
import datetime

def create_task(project, queue, location, payload=None, in_seconds=None):
    client = tasks_v2.CloudTasksClient()

    parent = client.queue_path(project, location, queue)

    task = 
            'app_engine_http_request': 
                'http_method': 'POST',
                'relative_uri': '/task/'+queue
            
    
    if payload is not None:
        converted_payload = payload.encode()

        task['app_engine_http_request']['body'] = converted_payload

    if in_seconds is not None:
        d = datetime.datetime.utcnow() + datetime.timedelta(seconds=in_seconds)

        timestamp = timestamp_pb2.Timestamp()
        timestamp.FromDatetime(d)

        task['schedule_time'] = timestamp

    response = client.create_task(parent, task)

    print('Created task '.format(response.name))
    print(response)

#You can change DOCUMENT_ID with USER_ID or something to identify the task
create_task(PROJECT_ID, QUEUE, REGION, DOCUMENT_ID)

【讨论】:

感谢您的反馈。然而,在我们的案例中,我们的主要业务需求是避免发送多封电子邮件,这可能是由于 Cloud Functions 触发写入触发器而独立更新 Firestore 文档而导致的。我们曾希望 Cloud Tasks 允许我们推迟发送电子邮件,同时使用基于 doc id 的命名任务对队列进行重复数据删除。如果我们每次都使用唯一的任务名称,那么将 doc id(或其他任何内容)放入有效负载中并不能解决我们的重复数据删除需求。由于您正在确认限制,因此将您的答案标记为答案。 @Gatmando 在不影响内置重复数据删除的情况下,您是否找到了任何解决方法。我也面临同样的问题,***.com/questions/69587915/… 不是真的:/ 原因是这个条件是在 Cloud Tasks 内部检查的,而不是我们可以配置的。如果 Pub/Sub 适合您,也许 Pub/Sub 可以成为另一种选择 不能使用 pubsub。我们需要延迟执行。我们还需要重复数据删除。我们的场景是这样的,对于在一毫秒内发生的 10 个新的 Firestore 插入,我们只需要创建一个任务来处理所有 10 个。任务名称基于父集合id @Oooha。不,我们没有找到解决办法。由于时间限制,我们最终使用 Firestore 创建了自己的自定义队列,这是一种可怕的方法,但现在可以使用。已经一年多了,我一直想深入研究这个问题,看看 GCP 的 Cloud Tasks 服务中是否有任何改变,现在可能允许这样做。如果我发现新的东西,我会更新。

以上是关于GCP Cloud Tasks:缩短创建先前创建的命名任务的时间的主要内容,如果未能解决你的问题,请参考以下文章

ImportError:无法从“google.cloud”导入名称“tasks_v2”

使用 Firebase 对 GCP Cloud 函数进行双重定价

用于计划发布的 Firebase 和 GCP Cloud 任务

Terraform GCP:无需用户停机即可更新 Cloud Run 服务

GCP Cloud Scheduler API 问题

如何使用 Cloud Build 在 GCP 上部署功能?