Durable Functions のタイマー (Azure Functions)

Durable Functions には、遅延を実装したり、非同期アクションでタイムアウトを設定したりできるように、オーケストレーター関数で使用する "持続的タイマー" が用意されています。 オーケストレーター関数では、言語に組み込まれている可能性がある "sleep" または "delay" API ではなく、持続的タイマーを使用する必要があります。

持続的タイマーは、以下に示すように、提供されている言語に対して適切な "create timer" API を使用して作成され、期限または期間を引数として受け取るタスクです。

// Put the orchestrator to sleep for 72 hours
DateTime dueTime = context.CurrentUtcDateTime.AddHours(72);
await context.CreateTimer(dueTime, CancellationToken.None);

タイマー タスクを "待機" すると、オーケストレーター関数は、指定された有効期限までスリープ状態になります。

Note

オーケストレーションは、タイマー タスクの有効期限が切れるのを待っている間、他の受信イベントを処理し続けます。

タイマーの制限事項

協定世界時午後 4 時 30 分に期限切れになるタイマーを作成すると、基になる Durable Task Framework によって、協定世界時午後 4 時 30 分にのみ表示されるメッセージがエンキューされます。 その間に関数アプリが 0 個のインスタンスにスケールダウンされた場合、新しく表示されるタイマー メッセージによって、関数アプリが適切な VM で再度アクティブ化されます。

Note

  • JavaScript、Python、PowerShell アプリの場合、持続的タイマー は 6 日間に制限されます。 この制限を回避するには、while ループでタイマー API を使用して、より長い遅延をシミュレートできます。 最新の .NET と Java の各アプリでは、任意の長いタイマーがサポートされています。
  • 使用されている SDK のバージョンとストレージ プロバイダーによっては、一連の短いタイマー (3 日間など) を目的の有効期限に達するまで使用して、6 日以上の長いタイマーが内部的に実装されている場合があります。 これは基になるデータ ストアで確認できますが、オーケストレーションの動作には影響しません。
  • 現在の時刻を取得するために組み込みの日付/時刻 API を使用しないでください。 タイマーの有効期限が切れる将来の日付を計算するときは、必ずオーケストレーター関数の現在の時刻 API を使用してください。 詳細については、「オーケストレーター関数コードの制約」の記事を参照してください。

遅延の使用

次の例は、実行を遅らせる持続的タイマーを使用する方法を示しています。 この例では、10 日間、請求の通知を毎日発行します。

[FunctionName("BillingIssuer")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    for (int i = 0; i < 10; i++)
    {
        DateTime deadline = context.CurrentUtcDateTime.Add(TimeSpan.FromDays(1));
        await context.CreateTimer(deadline, CancellationToken.None);
        await context.CallActivityAsync("SendBillingEvent");
    }
}

Note

前記の C# の例は Durable Functions 2.x をターゲットにしています。 Durable Functions 1.x の場合、IDurableOrchestrationContext の代わりに DurableOrchestrationContext を使用する必要があります。 バージョン間の相違点の詳細については、Durable Functions のバージョンに関する記事を参照してください。

警告

オーケストレーター関数の無限ループが発生しなようにしてください。 無限ループ シナリオを安全かつ効率的に実装する方法については、永続的オーケストレーションに関するページをご覧ください。

タイムアウトの使用

この例は、持続的タイマーを使用して、タイムアウトを実装する方法を示しています。

[FunctionName("TryGetQuote")]
public static async Task<bool> Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    TimeSpan timeout = TimeSpan.FromSeconds(30);
    DateTime deadline = context.CurrentUtcDateTime.Add(timeout);

    using (var cts = new CancellationTokenSource())
    {
        Task activityTask = context.CallActivityAsync("GetQuote");
        Task timeoutTask = context.CreateTimer(deadline, cts.Token);

        Task winner = await Task.WhenAny(activityTask, timeoutTask);
        if (winner == activityTask)
        {
            // success case
            cts.Cancel();
            return true;
        }
        else
        {
            // timeout case
            return false;
        }
    }
}

Note

前記の C# の例は Durable Functions 2.x をターゲットにしています。 Durable Functions 1.x の場合、IDurableOrchestrationContext の代わりに DurableOrchestrationContext を使用する必要があります。 バージョン間の相違点の詳細については、Durable Functions のバージョンに関する記事を参照してください。

警告

.NET、JavaScript、Python、PowerShell では、コードが作成された持続的タイマーの完了を待機しない場合、それらを取り消す必要があります。 保留中のタイマーを取り消す方法については、上記の例を参照してください。 Durable Task Framework では、持続的タイマー タスクを含め、未処理のタスクすべてが完了するかキャンセルされるまで、オーケストレーションの状態は "完了" に変更されません。

"when-any" パターンを使用するこのキャンセル メカニズムは、進行中のアクティビティ関数またはサブオーケストレーションの実行は終了させません。 オーケストレーター関数が、単に結果を無視して、次に進めるようにするだけです。 関数アプリが従量課金プランを使用している場合は、アクティビティ関数を破棄しても、その関数によって消費される時間とメモリはすべて課金対象となります。 既定では、従量課金プランで実行されている関数のタイムアウトは、5 分に設定されています。 この制限を超えると、Azure Functions ホストは、すべての実行を停止し、ランナウェイ課金状況を回避するために、リサイクルされます。 関数のタイムアウトは構成可能です。

オーケストレーター関数でタイムアウトを実装する方法の詳細な例については、人による操作とタイムアウト - 電話検証に関する記事を参照してください。

次のステップ