👻

Azure Functions TimerTriggerのCron式を外部ファイル・環境変数で管理する方法

2025/01/29に公開

1. はじめに

Azure Functions の Timer Trigger を利用する際、Cron 式host.json に直接記載するケースが多いですが、開発・運用の観点で以下のような課題が生まれることがあります。

  • 定期実行のスケジュールを変更したい時に、コードを修正・再デプロイしなければならない
  • 複数の環境(開発、ステージング、本番など)で異なるスケジュールを設定したい

こうした場合、Cron 式を外部ファイルや環境変数から読み込むことで、デプロイなしでの変更や環境ごとの設定を分離することができます。

この記事では、環境変数appsettings.json を使って Cron 式を設定する方法を、C#(.NET Isolated Worker)での Azure Functions サンプルコードとともにご紹介します。

2. Cron 式の基本的な書き方

Azure Functions の Timer Trigger では、以下のように Cron 式 を設定します。

[Function("SampleTimerTrigger")]
public static void Run(
    [TimerTrigger("0 0 * * * *")] TimerInfo timerInfo,
    FunctionContext context)
{
    var logger = context.GetLogger("SampleTimerTrigger");
    logger.LogInformation($"TimerTrigger fired at: {DateTime.UtcNow}");
}

上記の "0 0 * * * *" は、1時間ごとに実行される Cron 式を表しています。Azure Functions での Cron 式は、を含む 6 要素指定である点にご注意ください。

https://crontab.guru/

3. Cron 式を外部から設定する方法

3-1. 環境変数から読み込む

■ 手順

  1. local.settings.json や Azure Portal の「Configuration」タブで、環境変数として Cron 式を定義する
    • 例: local.settings.json
      {
        "IsEncrypted": false,
        "Values": {
          "AzureWebJobsStorage": "UseDevelopmentStorage=true",
          "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
          "CRON_EXPRESSION": "0 0 * * * *"
        }
      }
      
    • Azure Portal 上でも同様に CRON_EXPRESSION のキーと値を設定可能
  1. TimerTrigger の属性に、%...% の形で環境変数名を指定する

■ コード例

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

namespace MyFunctionApp
{
    public static class TimerTriggerSample
    {
        [Function("TimerTriggerSample")]
        public static void Run(
            [TimerTrigger("%CRON_EXPRESSION%")] TimerInfo timerInfo, 
            FunctionContext context)
        {
            var logger = context.GetLogger("TimerTriggerSample");
            logger.LogInformation($"TimerTrigger fired at: {DateTime.UtcNow}");

            // TimerInfoの詳細が欲しければ、以下のようにアクセス可能
            if (timerInfo.IsPastDue)
            {
                logger.LogInformation("Timer is running late!");
            }
            
            // 実行したい処理をここに記述
            // ...
        }
    }
}

3-2. appsettings.json(.NET Isolated Workerの例)

■ 手順

  1. appsettings.json をプロジェクトに追加し、Cron 式を記載する

    • 例: appsettings.json
      {
        "CronSettings": {
          "Schedule": "0 0 * * * *"
        }
      }
      
  2. Program.cs 等で ConfigurationBuilder による設定ファイル読み込みを行う(.NET Isolated Worker の場合)

    using Microsoft.Azure.Functions.Worker.Configuration;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Hosting;
    
    public class Program
    {
        public static void Main()
        {
            var host = new HostBuilder()
                .ConfigureFunctionsWorkerDefaults()
                .ConfigureAppConfiguration((context, configBuilder) =>
                {
                    configBuilder
                        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                        .AddEnvironmentVariables();
                })
                .Build();
    
            host.Run();
        }
    }
    
  3. 読み込んだ設定値を環境変数へブリッジする、あるいは直接コード内で使用する

    • 環境変数へブリッジして TimerTrigger 属性で %...% として参照するか、
    • または TimerTrigger 属性に直接文字列を埋め込む形で利用するか(属性には動的に入れられないため、一工夫必要)

■ ブリッジ方法の例

Program.cs や Startup ロジックなどで Configuration["CronSettings:Schedule"] を読み込み、環境変数として上書きするやり方です。

// Program.cs の ConfigureAppConfiguration 後
var schedule = host.Services
                  .GetService<IConfiguration>()?
                  ["CronSettings:Schedule"];

// Environment.SetEnvironmentVariable("CRON_EXPRESSION", schedule);
// ここで Environment に書き込むことで、Attribute の %CRON_EXPRESSION% から読めるようにする

そして、関数では以下のように記述します。

[Function("TimerTriggerSample")]
public static void Run(
    [TimerTrigger("%CRON_EXPRESSION%")] TimerInfo timerInfo,
    FunctionContext context)
{
    var logger = context.GetLogger("TimerTriggerSample");
    logger.LogInformation($"TimerTrigger fired at: {DateTime.UtcNow}");
    
    // ...
}

4. 運用のポイント

  1. local.settings.json はローカル開発専用

    • Azure Functions では local.settings.json は開発時専用ファイルとして扱われ、Azure にデプロイしてもアップロードされません。
    • 本番環境では Azure Portal の「設定」 (Configuration) か Key Vault などで管理しましょう。
  2. appsettings.json を使う場合の注意

    • こちらは .NET Isolated Worker の場合に有効で、かつ独自に ConfigurationBuilder を設定する必要があります。
    • In-process モデルの場合は、直接 local.settings.json や Azure Portal での環境変数設定を利用するほうがシンプルです。
  3. 同じキーで値を変更した場合は再起動が必要な場合も

    • Azure Functions は動的に再起動されることがありますが、TimerTrigger の Cron 式反映タイミングによっては再起動や数分のラグが生じる可能性があります。
    • スケジュール変更時は、念のため一度関数を再デプロイ・再起動すると安全です。

5. まとめ

  • Cron 式 を外部ファイルや環境変数に置くことで、デプロイなしでスケジュール変更が可能になります。
  • .NET In-process の場合は、local.settings.json もしくは Azure Portal の構成設定で %...% を指定するのが一般的です。
  • .NET Isolated Worker の場合は、ConfigurationBuilder で appsettings.json を読み込み、必要に応じて環境変数へブリッジして TimerTrigger に反映する方法が王道なのかなと思います。

外部化することで環境ごとのスケジュール差分を容易に管理できるため、運用負荷の軽減変更のスピードアップにつながります。ぜひ活用してみてください!

リファレンス

https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-timer?tabs=csharp

https://crontab.guru/

https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-best-practices#general-configuration-settings

GitHubで編集を提案

Discussion