快速入门:使用 Azure Functions 运行计划的任务

本文使用 Azure 开发人员 CLI (azd) 创建计时器触发器函数,以在 Azure Functions 中运行计划任务。

项目源用于 azd 创建函数应用和相关资源,并将代码部署到 Azure。 此部署遵循安全且可缩放的 Azure Functions 部署的当前最佳做法。

本文支持适用于 Azure Functions 的 Node.js 编程模型版本 4。

本文支持适用于 Azure Functions 的 Python 编程模型版本 2。

先决条件

  • Java 17 开发工具包
    • 如果您使用的是其他受支持的 Java 版本,则必须更新项目配置。
    • 将 JAVA_HOME 环境变量设置为正确版本的 Java 开发工具包(JDK)的安装位置。
  • Apache Maven 3.8.x

初始化项目

azd init使用命令从模板创建本地 Azure Functions 代码项目。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-dotnet-azd-timer -e scheduled-dotnet
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 运行以下命令以导航到应用文件夹:

    cd src
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
            "TIMER_SCHEDULE": "*/30 * * * * *"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-typescript-azd-timer -e scheduled-ts
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "node",
            "TIMER_SCHEDULE": "*/30 * * * * *"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-python-azd-timer -e scheduled-py
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "python",
            "TIMER_SCHEDULE": "*/30 * * * * *"
        }
    }
    

    在本地运行时,需要此文件。

创建并激活虚拟环境

在根文件夹中,运行以下命令以创建并激活一个名为 .venv 的虚拟环境:

python3 -m venv .venv
source .venv/bin/activate

如果 Python 未在 Linux 分发版上安装 venv 包,请运行以下命令:

sudo apt-get install python3-venv
  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-java-azd-timer -e scheduled-java
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 运行以下命令以导航到应用文件夹:

    cd src
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "java",
            "TIMER_SCHEDULE": "*/30 * * * * *"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-javascript-azd-timer -e scheduled-js
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "node",
            "TIMER_SCHEDULE": "*/30 * * * * *"
        }
    }
    

    在本地运行时,需要此文件。

  1. 在本地终端或命令提示符下,在空文件夹中运行此 azd init 命令:

    azd init --template functions-quickstart-powershell-azd-timer -e scheduled-ps
    

    此命令从模板存储库中拉取项目文件,并在当前文件夹中初始化项目。 -e 标志设置当前环境的名称。 在 azd,环境维护您应用程序的独特部署上下文,并且您可以定义多个。 环境名称还用于在 Azure 中创建的资源组的名称。

  2. 运行以下命令以导航到应用文件夹:

    cd src
    
  3. 在包含此 JSON 数据的 文件夹中创建名为 local.settings.json src的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "AzureWebJobsStorage": "UseDevelopmentStorage=true",
            "FUNCTIONS_WORKER_RUNTIME": "powershell",
            "TIMER_SCHEDULE": "*/30 * * * * *"
        }
    }
    

    在本地运行时,需要此文件。

在本地环境中运行

  1. 在单独的终端窗口中,启动 Azurite 存储模拟器:

    azurite
    

    本地 Functions 宿主进程将 Azurite 模拟器用于运行时所需的内部存储连接(AzureWebJobsStorage)。

  1. 在终端或命令提示符下从应用文件夹运行以下命令:

    func start
    
  1. 在终端或命令提示符下从应用文件夹运行以下命令:

    mvn clean package
    mvn azure-functions:run
    
  1. 在终端或命令提示符下从应用文件夹运行以下命令:

    npm install
    func start  
    
  1. 在终端或命令提示符下从应用文件夹运行以下命令:

    npm install
    npm start  
    
  1. 当 Functions 主机在本地项目文件夹中启动时,它会将有关计时器触发的函数的信息写入终端输出。 应会看到计时器触发的函数根据代码中定义的计划执行。

    默认计划是 */30 * * * * *每 30 秒运行一次。

  2. 完成后,在终端窗口中按 Ctrl+C 停止 func.exe 主机进程。

  1. 运行 deactivate 以关闭虚拟环境。

查看代码(可选)

可以查看定义计时器触发器函数的代码:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Extensions.Timer;
using Microsoft.Extensions.Logging;

namespace Company.Function
{
    public class timerFunction
    {
        private readonly ILogger _logger;

        public timerFunction(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<timerFunction>();
        }

        [Function("timerFunction")]
        public void Run(
            [TimerTrigger("%TIMER_SCHEDULE%", RunOnStartup = true)] TimerInfo myTimer,
            FunctionContext context
        )
        {
            _logger.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

            if (myTimer.IsPastDue)
            {
                _logger.LogWarning("The timer is running late!");
            }
        }
    }
}

可在此处查看完整的模板项目。

package com.function;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.TimerTrigger;
import java.time.LocalDateTime;

/**
 * Timer-triggered Azure Function that demonstrates scheduled execution.
 */
public class TimerFunction {
    @FunctionName("timerFunction")
    public void run(
            @TimerTrigger(name = "timerInfo", schedule = "%TIMER_SCHEDULE%") String timerInfo,
            final ExecutionContext context) {

        context.getLogger().info("Java Timer trigger function executed at: " + LocalDateTime.now());

        if (timerInfo != null && timerInfo.contains("\"isPastDue\":true")) {
            context.getLogger().warning("The timer is running late!");
        }
    }
}

可在此处查看完整的模板项目。

const { app } = require('@azure/functions');
async function timerFunction(myTimer, context) {
    context.log(`JavaScript Timer trigger function executed at: ${new Date().toISOString()}`);

    if (myTimer.isPastDue) {
        context.warn("The timer is running late!");
    }
}

app.timer('timerFunction', {
    schedule: '%TIMER_SCHEDULE%',
    runOnStartup: true,
    handler: timerFunction,
});

可在此处查看完整的模板项目。

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

export async function timerFunction(myTimer: Timer, context: InvocationContext): Promise<void> {
    context.log(`TypeScript Timer trigger function executed at: ${new Date().toISOString()}`);

    if (myTimer.isPastDue) {
        context.warn("The timer is running late!");
    }
}

app.timer('timerFunction', {
    schedule: '%TIMER_SCHEDULE%',
    runOnStartup: true,
    handler: timerFunction
});

可在此处查看完整的模板项目。

# 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 executed at: $currentUTCtime"

计时器触发器在相应的 function.json 中定义。

可在此处查看完整的模板项目。

import datetime
import logging

import azure.functions as func

# Create the function app instance
app = func.FunctionApp()

@app.timer_trigger(schedule="%TIMER_SCHEDULE%", 
                   arg_name="mytimer", 
                   run_on_startup=True,
                   use_monitor=False) 
def timer_function(mytimer: func.TimerRequest) -> None:
    utc_timestamp = datetime.datetime.now(datetime.timezone.utc).isoformat()

    logging.info(f'Python timer trigger function executed at: {utc_timestamp}')

    if mytimer.past_due:
        logging.warning('The timer is running late!')

可在此处查看完整的模板项目。

小窍门

此选项 runOnStartup 在开发和测试期间非常有用,因为该函数在主机启动时会立即运行。 在生产环境中,应将此设置为 false 避免在部署或重启期间出现意外执行。

在本地验证函数后,是时候将其发布到 Azure 了。

部署到 Azure 云

此项目使用Bicep文件和azd up命令在遵循最佳做法的消耗计划中为新的函数应用创建安全部署。

  1. 运行以下命令,让 azd 在 Azure 中创建所需的 Azure 资源,并将代码项目部署到新的函数应用:

    azd up
    

    根文件夹包含 azure.yaml 所需的 azd 定义文件。

    如果尚未登录,系统会要求使用 Azure 帐户进行身份验证。

  2. 出现提示时,请提供以下所需的部署参数:

    参数 Description
    Azure 订阅 要在其中创建资源的订阅。
    Azure 位置 要在其中创建包含新 Azure 资源的资源组的 Azure 区域。

    azd up 命令使用你对这些提示的回复和 Bicep 配置文件来完成这些部署任务:

    • 创建和配置这些所需的 Azure 资源(等效于 azd provision):

      • Azure 存储(必需)和 应用程序洞察(推荐)
      • 帐户的访问策略和角色
      • 使用托管标识(而不是存储的连接字符串)的服务到服务连接
      • 安全运行函数应用和其他 Azure 资源的虚拟网络
    • 打包代码并将其部署到部署容器(等效于 azd deploy)。 然后,应用将启动并在已部署的包中运行。

    命令成功完成后,你会看到指向所创建资源的链接。

验证部署

部署完成后,计时器触发器函数会根据其计划自动在 Azure 中运行。

  1. 在 Azure 门户中,转到新的函数应用。

  2. 从左侧菜单中选择 日志流 ,实时监视函数执行。

  3. 应会看到日志条目,这些日志条目显示计时器触发器函数根据其计划执行。

重新部署代码

azd up根据需要多次运行命令,以便预配 Azure 资源并将代码更新部署到函数应用。

注释

已部署的代码文件始终被最新的部署包覆盖。

对 azd 提示的初始响应和 azd 生成的任何环境变量都本地存储在你的命名环境中。 使用 azd env get-values 命令查看创建 Azure 资源时使用的环境中的所有变量。

清理资源

使用完函数应用和相关资源后,请使用此命令从 Azure 中删除函数应用及其相关资源,并避免产生任何进一步的成本:

azd down --no-prompt

注释

--no-prompt 选项指示 azd 在未经你确认的情况下删除资源组。

此命令不会影响本地代码项目。