Azure Functions 的计时器触发器

本文介绍如何在 Azure Functions 中使用计时器触发器。 计时器触发器可以按计划运行函数。

此参考信息面向 Azure Functions 开发人员。 Azure Functions 的新手请从以下资源入手:

若要了解如何手动运行计时器触发的函数,请参阅手动运行非 HTTP 触发的函数

在所有开发环境中自动提供对该绑定的支持。 无需手动安装包或注册扩展。

azure-webjobs-sdk-extensions GitHub 存储库中提供了计时器扩展包的源代码。

重要

本文使用选项卡来支持多个版本的 Node.js 编程模型。 v4 模型目前处于预览状态,旨在为 JavaScript 和 TypeScript 开发人员提供更为灵活和直观的体验。 在升级指南中详细了解 v3 和 v4 之间的差异。

Azure Functions 支持两种 Python 编程模型。 定义绑定的方式取决于选择的编程模型。

使用 Python v2 编程模型,可以直接在 Python 函数代码中使用修饰器定义绑定。 有关详细信息,请参阅 Python 开发人员指南

本文同时支持两个编程模型。

示例

此示例演示一个 C# 函数,每次分钟数为 5 的倍数值时执行该函数。 例如,当函数从 18:55:00 开始时,下一次执行为 19:00:00。 TimerInfo 对象将传递到函数中。

可以使用以下 C# 模式之一创建 C# 函数:

  • 进程内类库:编译的 C# 函数,该函数在与 Functions 运行时相同的进程中运行。
  • 独立进程类库:编译的 C# 函数,该函数在独立于运行时的进程中运行。 支持在 .NET 5.0 上运行的 C# 函数需要独立的进程。
  • C# 脚本:主要在 Azure 门户中创建 C# 函数时使用。
        //<docsnippet_fixed_delay_retry_example>
        [Function(nameof(TimerFunction))]
        [FixedDelayRetry(5, "00:00:10")]
        public static void Run([TimerTrigger("0 */5 * * * *")] TimerInfo timerInfo,
            FunctionContext context)
        {
            var logger = context.GetLogger(nameof(TimerFunction));

以下示例函数的触发和执行间隔为 5 分钟。 函数上的 @TimerTrigger 注释使用与 CRON 表达式相同的字符串格式定义计划。

@FunctionName("keepAlive")
public void keepAlive(
  @TimerTrigger(name = "keepAliveTrigger", schedule = "0 */5 * * * *") String timerInfo,
      ExecutionContext context
 ) {
     // timeInfo is a JSON string, you can deserialize it to an object using your favorite JSON library
     context.getLogger().info("Timer is triggered: " + timerInfo);
}

以下示例显示了计时器触发器绑定和使用绑定的函数代码(其中表示计时器的实例传递给函数)。 该函数将写入日志信息,指示调用此函数是由于错过了计划发生时间。 该示例取决于使用的是 v1 还是 v2 Python 编程模型

import datetime
import logging
import azure.functions as func

app = func.FunctionApp()

@app.function_name(name="mytimer")
@app.timer_trigger(schedule="0 */5 * * * *", 
              arg_name="mytimer",
              run_on_startup=True) 
def test_function(mytimer: func.TimerRequest) -> None:
    utc_timestamp = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc).isoformat()
    if mytimer.past_due:
        logging.info('The timer is past due!')
    logging.info('Python timer trigger function ran at %s', utc_timestamp)

以下示例显示了计时器触发器 TypeScript 函数

import { app, InvocationContext, Timer } from '@azure/functions';

export async function timerTrigger1(myTimer: Timer, context: InvocationContext): Promise<void> {
    context.log('Timer function processed request.');
}

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    handler: timerTrigger1,
});

以下示例展示了计时器触发器 JavaScript 函数

const { app } = require('@azure/functions');

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    handler: (myTimer, context) => {
        context.log('Timer function processed request.');
    },
});

下面是 function.json 文件中的绑定数据:

{
    "schedule": "0 */5 * * * *",
    "name": "myTimer",
    "type": "timerTrigger",
    "direction": "in"
}

下面是 run.ps1 文件中的计时器函数代码:

# Input bindings are passed in via param block.
param($myTimer)

# Get the current universal time in the default string format.
$currentUTCtime = (Get-Date).ToUniversalTime()

# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled.
if ($myTimer.IsPastDue) {
    Write-Host "PowerShell timer is running late!"
}

# Write an information log with the current time.
Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime"

特性

进程内 C# 库使用 Microsoft.Azure.WebJobs.Extensions 中的 TimerTriggerAttribute 来定义函数,而独立工作进程 C# 库使用 Microsoft.Azure.Functions.Worker.Extensions.Timer 中的 TimerTriggerAttribute 来定义函数。 C# 脚本改为使用 function.json 配置文件

Attribute 属性 说明
计划 CRON 表达式TimeSpan 值。 只能对在应用服务计划中运行的函数应用使用 TimeSpan。 可以将计划表达式放在应用设置中并将此属性设置为用 % 符号括起的应用设置名称,例如 %ScheduleAppSetting%
RunOnStartup 如果为 true,则在运行时启动时调用此函数。 例如,当函数应用从由于无活动而进入的空闲状态醒来后,运行时会启动。 当函数应用由于函数更改而重新启动时,以及当函数应用横向扩展时。请谨慎使用。RunOnStartup 应该很少设置为 true(如果曾经设置过),特别是在生产中。
UseMonitor 设置为 truefalse 以指示是否应当监视计划。 计划监视在各次计划发生后会持续存在,以帮助确保即使在函数应用实例重新启动的情况下也能正确维护计划。 如果未显式设置,则对于重复周期间隔大于或等于 1 分钟的计划,默认值为 true。 对于每分钟触发多次的计划,默认值为 false

修饰符

仅适用于 Python v2 编程模型。

对于使用修饰器定义的 Python v2 功能,支持 schedule 上的以下属性:

properties 说明
arg_name 在函数代码中表示计时器对象的变量的名称。
schedule NCRONTAB 表达式TimeSpan 值。 只能对在应用服务计划中运行的函数应用使用 TimeSpan。 可以将计划表达式放在应用设置中并将此属性设置为用 % 符号括起的应用设置名称,例如此示例中的“%ScheduleAppSetting%”。
run_on_startup 如果为 true,则在运行时启动时调用此函数。 例如,当函数应用从由于无活动而进入的空闲状态醒来后,运行时会启动。 当函数应用由于函数更改而重新启动时,以及当函数应用横向扩展时。请谨慎使用。runOnStartup 应该很少设置为 true(如果曾经设置过),特别是在生产中。
use_monitor 设置为 truefalse 以指示是否应当监视计划。 计划监视在各次计划发生后会持续存在,以帮助确保即使在函数应用实例重新启动的情况下也能正确维护计划。 如果未显式设置,则对于重复周期间隔大于或等于 1 分钟的计划,默认值为 true。 对于每分钟触发多次的计划,默认值为 false

对于使用 function.json 定义的 Python 函数,请参阅配置部分。

批注

函数上的 @TimerTrigger 注释使用与 CRON 表达式相同的字符串格式定义 schedule。 该注释支持以下设置:

配置

仅适用于 Python v1 编程模型

下表说明了可以在传递给 app.timer() 方法的 options 对象上设置的属性。

properties 说明
schedule NCRONTAB 表达式TimeSpan 值。 只能对在应用服务计划中运行的函数应用使用 TimeSpan。 可以将计划表达式放在应用设置中并将此属性设置为用 % 符号括起的应用设置名称,例如此示例中的“%ScheduleAppSetting%”。
runOnStartup 如果为 true,则在运行时启动时调用此函数。 例如,当函数应用从由于无活动而进入的空闲状态醒来后,运行时会启动。 当函数应用由于函数更改而重新启动时,以及当函数应用横向扩展时。请谨慎使用。runOnStartup 应该很少设置为 true(如果曾经设置过),特别是在生产环境中。
useMonitor 设置为 truefalse 以指示是否应当监视计划。 计划监视在各次计划发生后会持续存在,以帮助确保即使在函数应用实例重新启动的情况下也能正确维护计划。 如果未显式设置,则对于重复周期间隔大于或等于 1 分钟的计划,默认值为 true。 对于每分钟触发多次的计划,默认值为 false

下表解释了在 function.json 文件中设置的绑定配置属性。

“function.json”属性 说明
type 必须设置为“timerTrigger”。 在 Azure 门户中创建触发器时,会自动设置此属性。
direction 必须设置为“in”。 在 Azure 门户中创建触发器时,会自动设置此属性。
name 在函数代码中表示计时器对象的变量的名称。
schedule NCRONTAB 表达式TimeSpan 值。 只能对在应用服务计划中运行的函数应用使用 TimeSpan。 可以将计划表达式放在应用设置中并将此属性设置为用 % 符号括起的应用设置名称,例如此示例中的“%ScheduleAppSetting%”。
runOnStartup 如果为 true,则在运行时启动时调用此函数。 例如,当函数应用从由于无活动而进入的空闲状态醒来后,运行时会启动。 当函数应用由于函数更改而重新启动时,以及当函数应用横向扩展时。请谨慎使用。runOnStartup 应该很少设置为 true(如果曾经设置过),特别是在生产环境中。
useMonitor 设置为 truefalse 以指示是否应当监视计划。 计划监视在各次计划发生后会持续存在,以帮助确保即使在函数应用实例重新启动的情况下也能正确维护计划。 如果未显式设置,则对于重复周期间隔大于或等于 1 分钟的计划,默认值为 true。 对于每分钟触发多次的计划,默认值为 false

在本地开发时,需要将应用程序设置添加到 Values 集合中的 local.settings.json 文件中。

注意

请勿在生产环境中将 runOnStartup 设置为 true。 使用此设置会使代码在非常不可预测的时间执行。 在某些生产设置中,这些额外执行可能会导致消耗计划中托管的应用产生明显更高的成本。 例如,启用 runOnStartup 后,只要缩放函数应用,就会调用触发器。 在生产中启用 runOnStartup 之前,请确保完全了解函数的生产行为。

有关完整示例,请参阅示例部分

使用情况

调用计时器触发器函数时,计时器对象将传递到函数中。 以下 JSON 是计时器对象的示例表示形式。

{
    "Schedule":{
        "AdjustForDST": true
    },
    "ScheduleStatus": {
        "Last":"2016-10-04T10:15:00+00:00",
        "LastUpdated":"2016-10-04T10:16:00+00:00",
        "Next":"2016-10-04T10:20:00+00:00"
    },
    "IsPastDue":false
}
{
    "schedule":{
        "adjustForDST": true
    },
    "scheduleStatus": {
        "last":"2016-10-04T10:15:00+00:00",
        "lastUpdated":"2016-10-04T10:16:00+00:00",
        "next":"2016-10-04T10:20:00+00:00"
    },
    "isPastDue":false
}

如果当前函数调用晚于计划时间,则 isPastDue 属性为 true。 例如,函数应用重新启动可能会导致调用被错过。

NCRONTAB 表达式

Azure Functions 使用 NCronTab 库来解释 NCRONTAB 表达式。 NCRONTAB 表达式类似于 CRON 表达式,不同之处在于它在开头包含额外的第六个字段,用于以秒为单位的时间精度:

{second} {minute} {hour} {day} {month} {day-of-week}

每个字段可以具有下列类型之一的值:

类型 示例 何时触发
一个具体值 0 5 * * * * 一天中每小时的第 5 分钟
所有值 (*) 0 * 5 * * * 在第 5 小时期间,一小时的每一分钟
一个范围(- 运算符) 5-7 * * * * * 一分钟三次 - 每天每小时的每分钟的第 5 到 7 秒
一组值(, 运算符) 5,8,10 * * * * * 一分钟三次 - 每天每小时的每分钟的第 5、8 和 10 秒
一个间隔值(/ 运算符) 0 */5 * * * * 一小时 12 次 - 每天每小时的每 5分钟的第 0 秒

若要指定月份或天,可以使用数字值、名称或名称的缩写:

  • 对于天,数字值为 0 到 6,其中 0 表示星期日。
  • 名称采用英语。 例如:MondayJanuary
  • 名称不区分大小写。
  • 名称可缩写。 三字母是建议的缩写长度。 例如:MonJan

NCRONTAB 示例

以下是一些可用于 Azure Functions 中计时器触发器的 NCRONTAB 表达式示例。

示例 何时触发
0 */5 * * * * 每五分钟一次
0 0 * * * * 每小时一次(在每小时的开头)
0 0 */2 * * * 每两小时一次
0 0 9-17 * * * 从上午 9 点到下午 5 点每小时一次
0 30 9 * * * 每天上午 9:30
0 30 9 * * 1-5 每个工作日的上午 9:30
0 30 9 * Jan Mon 在一月份每星期一的上午 9:30

注意

NCRONTAB 表达式同时支持五字段和六字段格式 。 第六个字段的位置是秒的值,该值置于表达式的开头。 如果 CRON 表达式无效,则 Azure 门户函数测试将显示 404 错误,如果已连接 Application Insights,则会在那里记录更多详细信息。

NCRONTAB 时区

NCRONTAB 表达式中的数字指的是时间和日期,而不是时间跨度。 例如,hour 字段中的 5 指的是 5:00 AM,而不是每 5 小时。

CRON 表达式使用的默认时区为协调世界时 (UTC)。 若要让 CRON 表达式基于其他时区,请为你的函数应用创建一个名为 WEBSITE_TIME_ZONE 的应用设置。

此设置的值取决于运行函数应用的操作系统和计划。

操作系统 计划
Windows All 将该值设置为所需时区的名称,由 Windows 命令 tzutil.exe /L 给定的每个对的第二行指定

注意

Linux 消耗计划目前不支持 WEBSITE_TIME_ZONE

例如,美国东部时间(由 Eastern Standard Time (Windows) 或 America/New_York (Linux) 表示)当前在标准时间中使用 UTC-05:00,在夏令时中使用 UTC-04:00。 若要使计时器触发器每天在东部时间上午 10:00 触发,请为函数应用创建一个名为 WEBSITE_TIME_ZONE 的应用设置并将值设置为 Eastern Standard Time (Windows) 或 America/New_York (Linux),然后使用以下 NCRONTAB 表达式:

"0 0 10 * * *"

使用 WEBSITE_TIME_ZONE 时,时间将针对特定时区中的时间更改进行调整,包括夏令时和标准时间的更改。

TimeSpan

只能对在应用服务计划中运行的函数应用使用 TimeSpan

与 NCRONTAB 表达式不同,TimeSpan 值指定各次函数调用之间的时间间隔。 如果函数的运行时间超出了指定的时间间隔,则在函数完成时,计时器会立即再次调用该函数。

以字符串表示,当 hh 小于 24 时,TimeSpan 格式为 hh:mm:ss。 当前两个数字是 24 或更大的数字时,格式为 dd:hh:mm。 下面是一些示例:

示例 何时触发
"01:00:00" 每小时
"00:01:00" 每分钟
"25:00:00:00" 每 25 天
"1.00:00:00" 每天

横向扩展

如果函数应用横向扩展到多个实例,则在所有实例中只会运行由计时器触发的函数的单个实例。 如果有未完成的调用仍在运行,它将不会再次触发。

共享同一存储的函数应用

如果要在未部署到应用服务的函数应用之间共享存储帐户,则可能需要为每个应用显式分配主机 ID。

Functions 版本 设置
2.x(及更高版本) AzureFunctionsWebHost__hostid 环境变量
1.x host.json 中的 id

可以省略标识值,也可以手动将每个函数应用的标识配置设置为不同的值。

计时器触发器使用存储锁来确保当函数应用横向扩展到多个实例时将只有一个计时器实例。 如果两个函数应用共享相同的标识配置,并且每个函数应用都使用一个计时器触发器,则只有一个计时器运行。

重试行为

与队列触发器不同,计时器触发器在函数失败后不会重试。 函数失败时,在计划的下次时间到来前,不会再次调用该函数。

手动调用计时器触发器

Azure Functions 的计时器触发器提供了 HTTP Webhook,可以通过调用它来手动触发函数。 这在以下方案中非常有用。

  • 集成测试
  • 槽交换是冒烟测试或预热活动的一部分
  • 函数的初始部署,以立即在数据库中填充缓存或查找表

若要详细了解如何手动调用计时器触发的函数,请参阅手动运行非 HTTP 触发的函数

故障排除

有关在计时器触发器未按预期工作的情况下应采取的措施,请参阅调查和报告有关计时器触发功能未触发的问题

后续步骤