kokoni

クラウドおじさんの備忘録

Azure FunctionsのTimer Triggerで予期せず処理が実行されたときの対処方法

Azure FunctionsのTimer Triggerで再起動した時に処理が発火することがあるので調査した対処方法について記載していきます。

※この投稿は2020年1月4日時点の情報になります。

現象

Timer TriggerのFunctionsを明示的に停止→開始したりAzure側のメンテナンスで再起動がされた時にCronで設定している時間外で処理が実行されることがあります。結論からいうとこの現象には2つの要因があ ります。

UseMonitor

1つ目は「UseMonitor」という設定がデフォルトでTrueになっており、この設定がTrueの時は前回の実行時間及び次回実行時間をAzure Storageに保持しています。この保持した情報を元に次回実行時間を過ぎている場合、即時に実行されてしまうため予期しない時間に処理が開始されます。

「UseMonitor」自体は1分以上の間隔を持つTimer TriggerではTrueが推奨されています。「UseMonitor」については下記を参照してください。

docs.microsoft.com

前回の実行時間及び次回実行時間の情報はScheduleStatusで確認することができます。下記に確認用のサンプルソースを記載しておきます。

[FunctionName("Function1")]
public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, ILogger log)
{
    // 前回の実行時間
    log.LogInformation($"Last : {myTimer.ScheduleStatus.Last}");
    // 前回の実行ステータスの更新時間
    log.LogInformation($"LastUpdate : {myTimer.ScheduleStatus.LastUpdated}");
    // 今回実行予定時間
    log.LogInformation($"Next : {myTimer.ScheduleStatus.Next}");

    // 実行計画時間(Cron式の展開)
    log.LogInformation($"Schedule : {myTimer.Schedule}");
    //  現在時間が次回実行時間を越えているか判断
    log.LogInformation($"IsPastDue :{myTimer.IsPastDue}");
    // 次回実行時間を取得
    log.LogInformation($"GetNextOccurrence : {myTimer.Schedule.GetNextOccurrence(DateTime.Now)}");
}

こちらの対応方法としては「IsPastDue」というプロパティを見て判断するようにします。「IsPastDue」は次回実行時間が過ぎている場合にTrueになります。このフラグで判断して処理を完了するように対応すれば予期しない処理の実行は回避できます。

こちらの例にも書いてあるように実装すれば回避できます。

docs.microsoft.com

RunOnStartup

2つ目は「RunOnStartup 」がTrueになっている場合です。ローカル開発を行っているときによく利用する設定です。この設定をTrueにしておくと設定時間を待たずに即時実行してくれるので開発中は効率が良くなるのですが、設定を忘れたままリリースすると再起動や停止→実行をした時に実行されてしまいます。デフォルト設定ではFalseになっているので明示的にTrueにしない限りは影響はありませんが意外と気づかないので注意が必要になります。