快速入门:使用 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 在未经你确认的情况下删除资源组。

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