使用 cron.yaml 安排作业

借助 App Engine Cron 服务,您可以配置在指定时间或按固定时间间隔执行的定期计划任务。这些任务通常称为“Cron 作业”。这些 Cron 作业由 App Engine Cron 服务自动触发。例如,您可以使用该服务每天发送一封报告电子邮件,每 10 分钟更新一些缓存数据,或者每小时更新一些摘要信息。

Cron 作业将在一天中的指定时间使用 HTTP GET 请求调用网址。由 Cron 调用的 HTTP 请求可以运行最多 60 秒钟,并需要遵守与其他 HTTP 请求同样的限制

免费应用最多可以安排 20 个计划任务。付费应用最多可以安排 250 个计划任务。

cron 配置文件简介

位于应用根目录下的 cron.yaml 文件(和 app.yaml 文件一起)为您的自定义运行时应用配置计划任务。以下是一个 cron.yaml 文件示例:

cron:
- description: "daily summary job"
  url: /tasks/summary
  schedule: every 24 hours
- description: "monday morning mailout"
  url: /mail/weekly
  schedule: every monday 09:00
  timezone: Australia/NSW
- description: "new daily summary job"
  url: /tasks/summary
  schedule: every 24 hours
  target: beta

cron.yaml 文件采用 YAML 语法,由每个 Cron 作业的定义组成。每个作业定义必须包含一个 url 和一个 schedule。另外,您还可以视需要指定 descriptiontimezonetargetretry_parameters 等选项:

url
必需。您希望 Cron 服务将作业请求发送到的您的应用中的网址。
schedule
必需。定义作业运行的时间表,请参阅下面的语法
description
可选。描述您的 Cron 作业,可通过 GCP Console 查看这些作业。
timezone
可选。您希望在作业时间表中使用的时区名称或“zoneinfo”。如果未指定时区,则时间表将使用 UTC(也称为 GMT)。
target
可选。应用中特定服务的名称。如果指定了 target,则 Cron 服务会将作业请求定位到应用中的该服务。作业请求将路由到指定服务中配置为处理流量的版本。了解请求的路由方式。

有关 target 的重要注意事项:

  • 如果您启用了流量拆分,则您的作业请求不会被拆分到您配置的各个版本之间:
    • IP 地址拆分:来自 Cron 服务的作业请求始终从同一 IP 地址发送,因此这些作业请求每次都会路由到同一版本。
    • Cookie 拆分:作业请求不包含 Cookie,因此它们不会路由到其他任何版本。
  • 如果您使用调度文件,并且 dispatch.yaml 中也配置了同一网址,那么系统会重新路由您的作业。例如,如果在以下 cron.yamldispatch.yaml 文件中同时定义了 /tasks/hello_service2 网址,那么即使指定了 target: service1,作业请求也会被发送到 service2

    cron.yaml

    cron:
    - description: "test dispatch vs target"
      url: /tasks/hello_service2
      schedule: every 1 mins
      target: service1

    dispatch.yaml:

    dispatch:
    - url: '*/tasks/hello_service2'
      service: service2
retry_parameters
可选。指定该参数以重新运行失败的作业,请参阅下面的语法

定义 Cron 作业 schedule

Cron 作业按周期性时间间隔进行调度,并使用类似英文中的简单时间格式指定。您可以定义时间表,以便让您的作业每天运行多次,或在特定的日子和月份运行。

小于一天的时间间隔

使用小于一天的时间间隔,按重复性时间表每天多次运行作业。您可以定义结束时间间隔或开始时间间隔:

  • 结束时间间隔:定义一个作业的“结束时间”与下一个作业的开始时间之间的时间间隔,其中“结束时间”是指作业完成或超时的那个时间点。Cron 服务从 00:00 开始,全天(24 小时)以这种间隔运行作业,并在两个作业之间等待指定的时长。

    示例:对于 every 5 minutes 时间表,作业每天以 5 分钟为间隔运行。如果按此时间表运行的一个作业实例在 02:01 完成,则下一个作业将等待 5 分钟,于 02:06 再次开始运行。

  • 开始时间间隔:定义 Cron 服务启动每个作业的固定时间间隔。与结束时间间隔不同,如果采用开始时间间隔,则每次运行作业时不会考虑前一作业完成或超时的时间。您可以将作业设置为在时间范围内运行,也可以将其设置为在从 00:00 开始的全天(24 小时)内运行。

    由于严格限制了作业的开始时间,因此,如果作业的某个实例的运行时间超过了定义的时间间隔,则 Cron 服务可能会跳过作业。如果前一个作业尚未完成或超时,则会跳过间隔中的一个开始时间。

    示例:对于 every 5 minutes from 10:00 to 14:00 时间表,第一个作业在 10:00 开始运行,然后每 5 分钟开始运行下一个作业。如果第一个作业运行 7 分钟,则会跳过 10:05 的作业,因此,Cron 服务直到 10:10 才会运行该作业的另一个实例。

自定义时间间隔

您可以使用自定义时间间隔来定义时间表,让您的作业在一个或多个选定月份中的一个或多个选定日期每天运行一次。按自定义时间表运行的作业会全年运行,而且仅在选定月份和日期的特定时间运行。

示例:对于 1,2,3 of month 07:00 时间表,作业在每月前三天的 07:00 各运行一次。

有关 schedule 的重要注意事项:

  • 您必须决定是使用小于一天的时间间隔还是自定义时间间隔。不能将各种间隔类型的元素混用。例如,schedule: every 6 hours mon,wed,fri 这一时间表定义是无效的。
  • 任何时间都只能运行一个作业实例。Cron 服务设计为提供“至少一次”递送;也就是说,如果安排了某个作业,则 App Engine 会至少发送一次作业请求。在极少数情况下,可能会请求同一作业的多个实例,因此,您的请求处理程序应该具有幂等性,并且您的代码应确保在发生这种情况时不会产生任何造成错误的副作用。

设置 schedule 格式

如需指定作业的运行时间,则必须使用以下语法定义 schedule 元素:

schedule: [TYPE] [INTERVAL_VALUE] [INTERVAL_SCOPE]

选择一种间隔类型来定义 schedule 元素:

结束时间间隔
  • [TYPE]:每日间隔必须包含 every 前缀。

    示例:schedule: every 12 hours

  • [INTERVAL_VALUE]:整数值及相应的时间单位。时间单位的有效值包括:
    • minutesmins
    • hours
  • [INTERVAL_SCOPE]:不适用。如需设置作业开始运行的具体时间或运行时间范围,请参阅开始时间间隔自定义时间间隔的语法。
结束时间间隔示例
以下示例可帮助您了解如何定义使用结束时间间隔的作业时间表:
  • 每天 00:00 开始运行,每两个作业之间等待 5 分钟。每个作业结束后,Cron 服务等待 5 分钟后再运行下一个作业:
    schedule: every 5 minutes
  • 每天 00:00 开始运行,每两个作业之间等待 30 分钟。每个作业结束后,Cron 服务等待 30 分钟后再运行下一个作业:
    schedule: every 30 mins
开始时间间隔
  • [TYPE]:每日间隔必须包含 every 前缀。

    示例:schedule: every 12 hours

  • [INTERVAL_VALUE]:整数值及相应的时间单位。时间单位的有效值包括:
    • minutesmins
    • hours
  • [INTERVAL_SCOPE] 指定对应于 [INTERVAL_VALUE] 的子句。您可以自定义时间范围,或使用 24 小时 synchronized 选项。
    • 添加 from [HH:MM] to [HH:MM] 子句,以定义作业开始运行的具体时间和运行时间范围。

      您必须以 24 小时制指定时间值 (HH:MM),其中:

      • HH 是从 0023 的整数。
      • MM 是从 0059 的整数。
    • 使用 synchronized 指定 24 小时时间范围 (from 00:00 to 23:59),此范围按 [INTERVAL_VALUE] 值均分。

      重要提示:24 必须能被 [INTERVAL_VALUE] 整除,否则会发生错误。[INTERVAL_VALUE] 的有效值包括:1234681224

开始时间间隔示例
以下示例可帮助您了解如何定义使用开始时间间隔的作业时间表:
  • 每天 10:00 至 14:00,每 5 分钟运行一次:
    schedule: every 5 minutes from 10:00 to 14:00
  • 每天 08:00 至 16:00,每小时运行一次:
    schedule: every 1 hours from 08:00 to 16:00
  • 每天从 00:00 开始,每两小时运行一次:
    schedule: every 2 hours synchronized
自定义时间间隔
  • [TYPE]:自定义时间间隔可以包含 every 前缀以定义重复性间隔,或者您也可以定义一个月中特定日期的列表:
    • 如需定义重复性间隔,您可以使用 every 前缀。

      示例:

      schedule: every day 00:00
      schedule: every monday 09:00

    • 如需定义特定的天数,您必须使用序数。有效值为一个月的第一天到该月的最后一天,例如:
      • 1stfirst
      • 2ndsecond
      • 3rdthird
      • 一直到:31stthirtyfirst

      示例:

      schedule: 1st,3rd tuesday
      schedule: 2nd,third wednesday of month 09:00

  • [INTERVAL_VALUE]:自定义时间间隔包含您希望运行作业的特定天数或星期几的列表。该列表中的值必须用英文逗号隔开,该列表可以包含以下任何一种值:
    • 一个月中日期的整数值,最多 31 天,例如:
      • 1
      • 2
      • 3
      • 一直到:31
    • 混合使用以下任何完整值或简写值的日期名称:
      • mondaymon
      • tuesdaytue
      • wednesdaywed
      • thursdaythu
      • fridayfri
      • saturdaysat
      • sundaysun
      • 使用 day 指定一周中的所有日期。

    示例:

    schedule: 2nd monday,thu
    schedule: 1,8,15,22 of month 09:00
    schedule: 1st mon,wednesday,thu of sep,oct,nov 17:00

  • [INTERVAL_SCOPE]:指定对应于所指定 [INTERVAL_VALUE] 的子句。自定义时间间隔可以包括 of [MONTH] 子句,用于指定一年中的一个月,或以逗号分隔列表的形式指定多个月。您还必须定义希望运行作业的特定时间,例如:of [MONTH] [HH:MM]

    默认情况下,如果不包括 of 子句,则每月均按自定义时间间隔运行。

    • [MONTH]:必须使用英文逗号分隔列表来指定月份,并且可以混用以下完整值或简写值:
      • januaryjan
      • februaryfeb
      • marchmar
      • aprilapr
      • may
      • junejun
      • julyjul
      • augustaug
      • septembersep
      • octoberoct
      • novembernov
      • decemberdec
      • 使用 month 指定一年中的所有月份。
    • [HH:MM]:必须以 24 小时制指定时间值 (HH:MM),其中:
      • HH 是从 0023 的整数。
      • MM 是从 0059 的整数。
    • 示例:

      schedule: 1st monday of sep,oct,nov 09:00
      schedule: 1 of jan,april,july,oct 00:00

自定义时间间隔示例
以下示例可帮助您了解如何定义使用自定义时间间隔的作业时间表:
  • 每天 00:00 运行:
    schedule: every day 00:00
  • 每周一 09:00 运行:
    schedule: every monday 09:00
  • 在 3 月第二个星期三的 17:00 运行一次:
    schedule: 2nd wednesday of march 17:00
  • 在 5 月运行六次。在前两周的每周一、周三和周五 10:00 各运行一次:
    schedule: 1st,second mon,wed,fri of may 10:00
  • 每周运行一次。从每个月的第一天开始,每七天在 09:00 运行一次:
    schedule: 1,8,15,22 of month 09:00
  • 每隔一周运行一次。在每个月的第一个和第三个星期一的 04:00 各运行一次:
    schedule: 1st,third monday of month 04:00
  • 每年运行三次。在 9 月、10 月和 11 月第一个星期一的 09:00 各运行一次:
    schedule: 1st monday of sep,oct,nov 09:00
  • 每个季度运行一次。在 1 月、4 月、7 月和 10 月第一天的 00:00 各运行一次:
    schedule: 1 of jan,april,july,oct 00:00

指定重试

如果 Cron 作业的请求处理程序返回的状态代码不在 200-299(含边界值)范围内,则 App Engine 会判定该作业失败。默认情况下,系统不会重试失败的作业。您可以通过在配置文件中包含 retry_parameters 块来重试失败的作业。

下面是一个 cron.yaml 文件示例,其中包含一个 Cron 作业,该作业配置为最多重试五次(默认值),初始退避时间为 2.5 秒,每次加倍。

cron:
- description: "retry demo"
  url: /retry
  schedule: every 10 mins
  retry_parameters:
    min_backoff_seconds: 2.5
    max_doublings: 5

Cron 重试语法

下表介绍了重试参数。

元素 描述
job_retry_limit 失败的 Cron 作业的重试次数上限不超过“5”。如果与 job_age_limit 一起指定,则 App Engine 会重试 Cron 作业,直至同时达到这两个限制。如果参数中省略了此元素,则该限制默认设置为 5。
job_age_limit 重试失败的 Cron 作业的时间限制,从首次运行 Cron 作业开始计算。该值是一个数字后跟一个时间单位,时间单位可以是 s(秒)、m(分钟)、h(小时)或 d(天)。例如,值 5d 表示仅限在 Cron 作业首次尝试执行后的五天内进行重试。如果与 job_retry_limit 一起指定,则 App Engine 会重试 Cron 作业,直至同时达到这两个限制。
min_backoff_seconds Cron 作业失败后重试该作业之前等待的秒数下限。
max_backoff_seconds Cron 作业失败后重试该作业之前等待的秒数上限。
max_doublings 在增加量变为常量之前,失败的 Cron 作业重试之间的时间间隔将加倍的最大次数。该常量为:2**(max_doublings - 1) * min_backoff

验证 Cron 请求

您可能想要验证对 Cron 网址的请求是来自 App Engine 而不是其他来源。这可以通过验证请求的 HTTP 标头和源 IP 地址来实现:

  • 来自 Cron 服务的请求还包含下面的 HTTP 标头:

    X-Appengine-Cron: true
    

    X-Appengine-Cron 标头由 Google App Engine 在内部设置。如果您的请求处理程序找到了此标头,则可以信任该请求是 Cron 请求。如果 X- 标头源自外部,则此标头会被 App Engine 删除,因此您可以信任此标头。

  • Google App Engine 从 IP 地址 10.0.0.1 发出 Cron 请求。

上传 Cron 作业

如需上传 Cron 作业,您必须指定 cron.yaml 作为以下 gcloud 命令的参数:

gcloud app deploy cron.yaml

删除 Cron 作业

如需删除所有 Cron 作业,请将 cron.yaml 文件更改为仅包含以下内容:

cron:

显示作业信息

您可以使用 appcfg.py cron_info 命令显示 Cron 作业的解析版本,其中包含作业运行的时间。

请注意,如果指定的时区不是世界协调时间 (UTC),则 appcfg.py cron_info 将无法正确计算时间表。

Google Cloud Platform Console 中的 Cron 支持

您可以在 GCP Console 的“Cron 作业”页面上查看已安排的 Cron 作业。

您还可以访问“日志”页面,查看 Cron 作业的添加或移除时间。