オーケストレーション インスタンスの管理

組み込みのインスタンス管理 API を使用して、永続的なワークフローでオーケストレーション インスタンスの開始、クエリ、終了、中断、再開、および消去を行います。 Durable Functions では、orchestration クライアント バインドはこれらの API を公開します。 Durable Task SDK ではDurableTaskClient クラスを通じて同じ操作を使用できます。 この記事では、両方のプラットフォームのコード例を使用して各インスタンス管理操作を実行する方法について説明します。

ヒント

Azure Durable Task Scheduler は、Durable Functions SDK と Durable Task SDK の両方に推奨されるバックエンドであり、永続的なワークフローを大規模に実行するためのフル マネージドのサーバーレス エクスペリエンスを提供します。

インスタンスを開始する

オーケストレーション クライアント の start-new (または schedule-new) メソッドは、新しいオーケストレーション インスタンスを開始します。 内部的には、このメソッドは設定済みのバックエンド(例えばDurable Task Scheduler)にメッセージを書き込み、その後返します。 このメッセージは、指定した名前でオーケストレーションの開始を非同期的にトリガーします。

新しいオーケストレーション インスタンスを開始するためのパラメーターを次に示します。

パラメーター Description
氏名 スケジュールするオーケストレーター関数の名前。
入力 オーケストレーター関数の入力として渡すべきJSONシリアライズ可能なデータ。
InstanceId (任意)インスタンスの一意ID。 このパラメーターを指定しない場合、メソッドはランダム ID を使用します。

ヒント

可能な限り、インスタンス ID にランダムな識別子を使用します。 ランダム インスタンス ID は、複数の VM 間でオーケストレーター関数をスケーリングするときに、均等な負荷分散を実現するのに役立ちます。 非ランダム インスタンス ID を使用する適切なタイミングは、ID が外部ソースから取得されたとき、または シングルトン オーケストレーター パターンを実装する場合です。

パラメーター Description
氏名 スケジュールするオーケストレーションの名前。
入力 オーケストレーションに入力として渡すべきJSONシリアライズ可能なデータ。
InstanceId (任意)インスタンスの一意ID。 このパラメーターを指定しない場合、メソッドはランダム ID を使用します。

ヒント

可能な限り、インスタンス ID にランダムな識別子を使用します。 ランダム インスタンス ID は、複数の VM 間でオーケストレーションをスケーリングするときに、均等な負荷分散を実現するのに役立ちます。 非ランダム インスタンス ID を使用する適切なタイミングは、ID が外部ソースから取得されたとき、または シングルトン オーケストレーター パターンを実装する場合です。

次の例の関数は、新しいオーケストレーション インスタンスを開始します。

分離ワーカー モデル
[Function("HelloWorldQueueTrigger")]
public static async Task Run(
    [QueueTrigger("start-queue")] string input,
    [DurableClient] DurableTaskClient client,
    FunctionContext functionContext)
{
    string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("HelloWorld", input);
    functionContext.GetLogger("HelloWorldQueueTrigger")
        .LogInformation("Started orchestration with ID = '{InstanceId}'.", instanceId);
}

プロセス内モデル
[FunctionName("HelloWorldQueueTrigger")]
public static async Task Run(
    [QueueTrigger("start-queue")] string input,
    [DurableClient] IDurableOrchestrationClient starter,
    ILogger log)
{
    string instanceId = await starter.StartNewAsync("HelloWorld", input);
    log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
}

Important

現在、PowerShell Durable Task SDK は使用できません。

次のコードは、Durable Task SDK を使用して新しいオーケストレーション インスタンスを開始する方法を示しています。

using Microsoft.DurableTask.Client;

// Schedule a new orchestration instance
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("HelloWorld", input);
Console.WriteLine($"Started orchestration with ID = '{instanceId}'.");

// Optionally, wait for the orchestration to start
OrchestrationMetadata metadata = await client.WaitForInstanceStartAsync(instanceId, timeout: TimeSpan.FromSeconds(30));

クエリ インスタンス

新しいオーケストレーション インスタンスを開始した後は、ほとんどの場合、ランタイムの状態を照会して、それらが実行されているか、完了しているか、失敗しているかを確認する必要があります。

オーケストレーション クライアント の get-status メソッドは、オーケストレーション インスタンスの状態を返します。

パラメーターとして、 instanceId (必須)、 showHistory (省略可能)、 showHistoryOutput (省略可能)、および showInput (省略可能) を受け取ります。

  • showHistory: trueに設定されている場合、応答には実行履歴が含まれます。
  • showHistoryOutput: trueに設定すると、実行履歴にアクティビティの出力が含まれます。
  • showInput: falseに設定されている場合、応答には関数の入力は含まれません。 既定値は true です。

このメソッドは、次のプロパティを持つオブジェクトを返します。

財産 Description
氏名 オーケストレーター関数の名前です。
InstanceId オーケストレーションのインスタンスIDは( instanceId 入力と同じであるべきです)。
CreatedTime オーケストレーター関数が動作を開始する時刻。
LastUpdatedTime オーケストレーションの最後のチェックポイント時刻。
入力 関数の入力はJSON値です。 showInputfalseになっている場合、このフィールドは設定されません。
カスタムステータス JSON形式のカスタムオーケストレーション状況。
アウトプット 関数が完了した場合、JSON値として出力します。 オーケストレーター関数が失敗した場合、このプロパティにはエラーの詳細が含まれます。 オーケストレーター関数が中断または終了された場合、このプロパティには中断または終了の理由が含まれます (ある場合)。
RuntimeStatus: Pending インスタンスはスケジュールされていますが、まだ稼働は開始されていません。
RuntimeStatus: Running インスタンスは実行中です。
RuntimeStatus: 完了 インスタンスは正常に完了しました。
ランタイム状態: 新規として継続 インスタンスは新しい履歴で再起動しました。 この状態は一時的な状態です。
RuntimeStatus: 失敗 インスタンスはエラーで失敗しました。
RuntimeStatus: 終了済み インスタンスは突然停止した。
RuntimeStatus: 停止中 インスタンスは一時停止され、後で再開可能です。
歴史 オーケストレーションの実行経緯。 このフィールドは、 showHistorytrue に設定されている場合にのみ設定されます。
パラメーター Description
showHistory trueに設定されている場合、レスポンスには実行履歴が含まれます。
showHistoryOutput trueに設定されている場合、実行履歴にはアクティビティの出力が含まれます。
showInput falseに設定すると、応答にはオーケストレーションの入力が含まれません。 既定値は true です。

このメソッドは、次のプロパティを持つオブジェクトを返します。

財産 Description
氏名 編曲の名前。
InstanceId オーケストレーションのインスタンスIDは( instanceId 入力と同じであるべきです)。
CreatedTime オーケストレーションの実行開始時刻。
LastUpdatedTime オーケストレーションの最後のチェックポイント時刻。
入力 オーケストレーションの入力をJSON値として扱います。 showInputfalseになっている場合、このフィールドは設定されません。
カスタムステータス JSON形式のカスタムオーケストレーション状況。
アウトプット オーケストレーションの出力はJSON値として(オーケストレーションが完了した場合)。 オーケストレーションが失敗した場合、このプロパティにはエラーの詳細が含まれます。 オーケストレーションが中断または終了された場合、このプロパティには中断または終了の理由が含まれます (ある場合)。
RuntimeStatus: Pending インスタンスはスケジュールされていますが、まだ稼働は開始されていません。
RuntimeStatus: Running インスタンスは実行中です。
RuntimeStatus: 完了 インスタンスは正常に完了しました。
RuntimeStatus: ContinuedAsNew インスタンスは新しい履歴で再起動しました。 この状態は一時的な状態です。
RuntimeStatus: 失敗 インスタンスはエラーで失敗しました。
RuntimeStatus: 終了済み インスタンスは突然停止した。
RuntimeStatus: 停止中 インスタンスは一時停止され、後日再開可能です。
歴史 オーケストレーションの実行経緯。 このフィールドは、 showHistorytrue に設定されている場合にのみ設定されます。

オーケストレーターは、スケジュールされたすべてのタスクが完了Completedオーケストレーターが戻るまで、としてマークされません。 つまり、オーケストレーターが return とマークされるためには、Completed ステートメントに到達するだけでは不十分です。 これは、WhenAny が使用される場合に特に関連しています。これらのオーケストレーターは、多くの場合、スケジュールされたすべてのタスクが実行される前に return を行います。

このメソッドは、インスタンスが存在しない場合は、 null (.NET と Java)、 undefined (JavaScript)、または None (Python) を返します。

分離ワーカー モデル
[Function("GetStatus")]
public static async Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("check-status-queue")] string instanceId)
{
    OrchestrationMetadata? metadata = await client.GetInstanceAsync(
        instanceId,
        getInputsAndOutputs: true);
    // Do something based on the current status.
}

プロセス内モデル
[FunctionName("GetStatus")]
public static async Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("check-status-queue")] string instanceId)
{
    DurableOrchestrationStatus status = await client.GetStatusAsync(instanceId);
    // do something based on the current status.
}

using Microsoft.DurableTask.Client;

// Get the status of an orchestration instance
OrchestrationMetadata? metadata = await client.GetInstanceAsync(instanceId, getInputsAndOutputs: true);
if (metadata != null)
{
    OrchestrationRuntimeStatus status = metadata.RuntimeStatus;
    // do something based on the current status
}

すべてのオーケストレーション インスタンスに対してクエリを実行する

言語 SDK の API を使用して、 タスク ハブ内のすべてのオーケストレーション インスタンスの状態を照会できます。 この "list-instances" または "get-status" API は、クエリ パラメーターに一致するオーケストレーション インスタンスを表すオブジェクトの一覧を返します。

分離ワーカー モデル
[Function("GetAllStatus")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData request,
    [DurableClient] DurableTaskClient client,
    FunctionContext functionContext)
{
    ILogger logger = functionContext.GetLogger("GetAllStatus");
    AsyncPageable<OrchestrationMetadata> instances = client.GetAllInstancesAsync(
        new OrchestrationQuery());

    await foreach (OrchestrationMetadata instance in instances)
    {
        logger.LogInformation("{Instance}", instance);
    }
}

プロセス内モデル
[FunctionName("GetAllStatus")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
    [DurableClient] IDurableOrchestrationClient client,
    ILogger log)
{
    var noFilter = new OrchestrationStatusQueryCondition();
    OrchestrationStatusQueryResult result = await client.ListInstancesAsync(
        noFilter,
        CancellationToken.None);
    foreach (DurableOrchestrationStatus instance in result.DurableOrchestrationState)
    {
        log.LogInformation(JsonConvert.SerializeObject(instance));
    }

    // Note: ListInstancesAsync only returns the first page of results.
    // To request additional pages provide the result.ContinuationToken
    // to the OrchestrationStatusQueryCondition's ContinuationToken property.
}

using Microsoft.DurableTask.Client;

// Query all orchestration instances
AsyncPageable<OrchestrationMetadata> instances = client.GetAllInstancesAsync(new OrchestrationQuery());

await foreach (OrchestrationMetadata instance in instances)
{
    Console.WriteLine(instance.InstanceId);
}

フィルターを使用してオーケストレーション インスタンスにクエリを実行する

標準インスタンス クエリで提供されるすべての情報が必要ない場合はどうしますか? たとえば、オーケストレーションの作成時刻またはオーケストレーション ランタイムの状態だけを探している場合はどうなりますか。 フィルターを適用してクエリを絞り込みます。

分離ワーカー モデル
[Function("QueryStatus")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData request,
    [DurableClient] DurableTaskClient client,
    FunctionContext functionContext)
{
    ILogger logger = functionContext.GetLogger("QueryStatus");
    var query = new OrchestrationQuery
    {
        Statuses = new[]
        {
            OrchestrationRuntimeStatus.Pending,
            OrchestrationRuntimeStatus.Running,
        },
        CreatedFrom = DateTime.UtcNow.Subtract(TimeSpan.FromDays(7)),
        CreatedTo = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
        PageSize = 100,
    };

    await foreach (OrchestrationMetadata instance in client.GetAllInstancesAsync(query))
    {
        logger.LogInformation("{Instance}", instance);
    }
}

プロセス内モデル
[FunctionName("QueryStatus")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
    [DurableClient] IDurableOrchestrationClient client,
    ILogger log)
{
    // Get the first 100 running or pending instances that were created between 7 and 1 days ago
    var queryFilter = new OrchestrationStatusQueryCondition
    {
        RuntimeStatus = new[]
        {
            OrchestrationRuntimeStatus.Pending,
            OrchestrationRuntimeStatus.Running,
        },
        CreatedTimeFrom = DateTime.UtcNow.Subtract(TimeSpan.FromDays(7)),
        CreatedTimeTo = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
        PageSize = 100,
    };

    OrchestrationStatusQueryResult result = await client.ListInstancesAsync(
        queryFilter,
        CancellationToken.None);
    foreach (DurableOrchestrationStatus instance in result.DurableOrchestrationState)
    {
        log.LogInformation(JsonConvert.SerializeObject(instance));
    }
}

using Microsoft.DurableTask.Client;

// Get running or pending instances created in the last 7 days
var query = new OrchestrationQuery
{
    Statuses = new[] { OrchestrationRuntimeStatus.Running, OrchestrationRuntimeStatus.Pending },
    CreatedFrom = DateTime.UtcNow.AddDays(-7),
    CreatedTo = DateTime.UtcNow.AddDays(-1),
    PageSize = 100
};

AsyncPageable<OrchestrationMetadata> instances = client.GetAllInstancesAsync(query);

await foreach (OrchestrationMetadata instance in instances)
{
    Console.WriteLine($"{instance.InstanceId}: {instance.RuntimeStatus}");
}

オーケストレーション インスタンスを終了する

実行に時間がかかりすぎるオーケストレーション インスタンスがある場合、または何らかの理由で完了する前に停止する必要がある場合は、終了できます。

terminate API の 2 つのパラメーターは 、インスタンス ID理由 文字列であり、ログとインスタンスの状態に書き込まれます。

分離ワーカー モデル
[Function("TerminateInstance")]
public static Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("terminate-queue")] string instanceId)
{
    string reason = "Found a bug";
    return client.TerminateInstanceAsync(instanceId, reason);
}

プロセス内モデル
[FunctionName("TerminateInstance")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("terminate-queue")] string instanceId)
{
    string reason = "Found a bug";
    return client.TerminateAsync(instanceId, reason);
}

using Microsoft.DurableTask.Client;

string reason = "Found a bug";
await client.TerminateInstanceAsync(instanceId, reason);

終了したインスタンスは、最終的に Terminated 状態に遷移します。 ただし、この移行はすぐには行われません。 代わりに、終了操作は、そのインスタンスの他の操作と共にタスク ハブにキューに入れられます。 インスタンス クエリ API を使用して、終了したインスタンスが実際にTerminated状態に達したタイミングを把握できます。

インスタンスの終了は現在伝達されません。 アクティビティ関数とサブオーケストレーションは、呼び出したオーケストレーション インスタンスを終了するかどうかに関係なく、完了まで実行されます。

オーケストレーション インスタンスの中断と再開

オーケストレーションを中断すると、実行中のオーケストレーションを停止することができます。 オーケストレーションの終了とは異なり、中断されたオーケストレーターを後で再開することができます。

suspend API の 2 つのパラメーターは、インスタンス ID と理由文字列であり、ログとインスタンスの状態に書き込まれます。

分離ワーカー モデル
[Function("SuspendResumeInstance")]
public static async Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("suspend-resume-queue")] string instanceId)
{
    // To suspend an orchestration
    string suspendReason = "Need to pause workflow";
    await client.SuspendInstanceAsync(instanceId, suspendReason);

    // To resume an orchestration
    string resumeReason = "Continue workflow";
    await client.ResumeInstanceAsync(instanceId, resumeReason);
}

プロセス内モデル
[FunctionName("SuspendResumeInstance")]
public static async Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("suspend-resume-queue")] string instanceId)
{
    // To suspend an orchestration
    string suspendReason = "Need to pause workflow";
    await client.SuspendAsync(instanceId, suspendReason);

    // To resume an orchestration
    string resumeReason = "Continue workflow";
    await client.ResumeAsync(instanceId, resumeReason);
}

using Microsoft.DurableTask.Client;

// To suspend an orchestration
string suspendReason = "Need to pause workflow";
await client.SuspendInstanceAsync(instanceId, suspendReason);

// To resume an orchestration
string resumeReason = "Continue workflow";
await client.ResumeInstanceAsync(instanceId, resumeReason);

中断されたインスタンスは、最終的に Suspended 状態に遷移します。 ただし、この移行はすぐには行われません。 代わりに、中断操作は、そのインスタンスの他の操作と共にタスク ハブにキューに入れられます。 インスタンス クエリ API を使用して、実行中のインスタンスが実際に Suspended 状態に達したことを確認します。

中断されたオーケストレーターが再開されると、その状態が Runningに戻ります。

インスタンスにイベントを送信する

一部のシナリオでは、オーケストレーター関数が外部イベントを待ち、受信する必要があります。 このアプローチが役に立つ例としては、 監視人間の相互作用 のシナリオがあります。

一部のシナリオでは、オーケストレーションが外部イベントを待機してリッスンする必要があります。 このアプローチが役に立つ例としては、 監視人間の相互作用 のシナリオがあります。

オーケストレーション クライアントの raise イベント API を使用して、実行中のインスタンスに イベント 通知を送信できます。 オーケストレーションは、外部イベントの待機オーケストレーターAPIを使用して、これらのイベントを待ち受けて応答できます。

raise イベントのパラメーターは次のとおりです。

  • インスタンス ID: インスタンスの一意の ID。
  • イベント名: 送信するイベントの名前。
  • イベント データ: インスタンスに送信する JSON シリアル化可能なペイロード。
分離ワーカー モデル
[Function("RaiseEvent")]
public static Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("event-queue")] string instanceId)
{
    int[] eventData = new int[] { 1, 2, 3 };
    return client.RaiseEventAsync(instanceId, "MyEvent", eventData);
}

プロセス内モデル
[FunctionName("RaiseEvent")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("event-queue")] string instanceId)
{
    int[] eventData = new int[] { 1, 2, 3 };
    return client.RaiseEventAsync(instanceId, "MyEvent", eventData);
}

using Microsoft.DurableTask.Client;

int[] eventData = new int[] { 1, 2, 3 };
await client.RaiseEventAsync(instanceId, "MyEvent", eventData);

指定したインスタンス ID を持つオーケストレーション インスタンスがない場合、イベント メッセージは破棄されます。 インスタンスが存在するが、まだイベントを待機していない場合、イベントは受信して処理する準備ができるまでインスタンス状態に格納されます。

オーケストレーションの完了を待つ

実行時間の長いオーケストレーションでは、オーケストレーションの結果を待機して取得することが必要な場合があります。 このような場合は、オーケストレーションのタイムアウト期間を定義することも役立ちます。 タイムアウトを超えた場合は、結果ではなくオーケストレーションの状態が返されます。

オーケストレーション インスタンスから実際の出力を同期的に取得するには、 "完了の待機または状態の確認応答の作成" API を使用します。 既定では、このメソッドのタイムアウトは 10 秒で、ポーリング間隔は 1 秒です。

この API の使用方法を示す HTTP トリガー関数の例を次に示します。

分離ワーカー モデル
[Function("HttpSyncStart")]
public static async Task<HttpResponseData> Run(
    [HttpTrigger(
        AuthorizationLevel.Function,
        "post",
        Route = "orchestrators/{functionName}/wait")] HttpRequestData request,
    [DurableClient] DurableTaskClient client,
    string functionName)
{
    string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(functionName);

    using var timeoutCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30));
    return await client.WaitForCompletionOrCreateCheckStatusResponseAsync(
        request,
        instanceId,
        timeoutCancellation.Token);
}

プロセス内モデル
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;

namespace VSSample
{
    public static class HttpSyncStart
    {
        private const string Timeout = "timeout";
        private const string RetryInterval = "retryInterval";

        [FunctionName("HttpSyncStart")]
        public static async Task<HttpResponseMessage> Run(
            [HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}/wait")]
            HttpRequestMessage req,
            [DurableClient] IDurableOrchestrationClient starter,
            string functionName,
            ILogger log)
        {
            // Function input comes from the request content.
            object eventData = await req.Content.ReadAsAsync<object>();
            string instanceId = await starter.StartNewAsync(functionName, eventData);

            log.LogInformation($"Started orchestration with ID = '{instanceId}'.");

            TimeSpan timeout = GetTimeSpan(req, Timeout) ?? TimeSpan.FromSeconds(30);
            TimeSpan retryInterval = GetTimeSpan(req, RetryInterval) ?? TimeSpan.FromSeconds(1);
            
            return await starter.WaitForCompletionOrCreateCheckStatusResponseAsync(
                req,
                instanceId,
                timeout,
                retryInterval);
        }

        private static TimeSpan? GetTimeSpan(HttpRequestMessage request, string queryParameterName)
        {
            string queryParameterStringValue = request.RequestUri.ParseQueryString()[queryParameterName];
            if (string.IsNullOrEmpty(queryParameterStringValue))
            {
                return null;
            }

            return TimeSpan.FromSeconds(double.Parse(queryParameterStringValue));
        }
    }
}

Durable Task SDK には、オーケストレーションが同期的に完了するまで待機するメソッドが用意されています。

using Microsoft.DurableTask.Client;

// Wait for orchestration to complete with a timeout
OrchestrationMetadata metadata = await client.WaitForInstanceCompletionAsync(
    instanceId,
    timeout: TimeSpan.FromSeconds(30),
    getInputsAndOutputs: true);

if (metadata.RuntimeStatus == OrchestrationRuntimeStatus.Completed)
{
    Console.WriteLine($"Output: {metadata.SerializedOutput}");
}

次の行で関数を呼び出します。 タイムアウトには 2 秒、再試行間隔には 0.5 秒を使用します。

curl -X POST "http://localhost:7071/orchestrators/E1_HelloSequence/wait?timeout=2&retryInterval=0.5"

上記の cURL コマンドは、プロジェクトに E1_HelloSequence という名前のオーケストレーター関数があることを前提としています。 HTTP トリガー関数の記述方法により、プロジェクト内のオーケストレーター関数の名前に置き換えることができます。

オーケストレーション インスタンスから応答を取得するために必要な時間に応じて、次の 2 つのケースが存在します。

  • オーケストレーション インスタンスは、定義されたタイムアウト (この場合は 2 秒) 以内に終了し、応答は実際のオーケストレーション インスタンスの出力であり、同期的に配信されます。
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Thu, 14 Dec 2021 06:14:29 GMT
Transfer-Encoding: chunked

[
    "Hello Tokyo!",
    "Hello Seattle!",
    "Hello London!"
]
  • オーケストレーション インスタンスは定義されたタイムアウト内で終了できません。応答は、 HTTP API URL の検出で説明されている既定の応答です。
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
Date: Thu, 14 Dec 2021 06:13:51 GMT
Location: http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177?taskHub={taskHub}&connection={connection}&code={systemKey}
Retry-After: 10
Transfer-Encoding: chunked

{
    "id": "d3b72dddefce4e758d92f4d411567177",
    "sendEventPostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/raiseEvent/{eventName}?taskHub={taskHub}&connection={connection}&code={systemKey}",
    "statusQueryGetUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177?taskHub={taskHub}&connection={connection}&code={systemKey}",
    "terminatePostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/terminate?reason={text}&taskHub={taskHub}&connection={connection}&code={systemKey}",
    "suspendPostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/suspend?reason={text}&taskHub={taskHub}&connection={connection}&code={systemKey}",
    "resumePostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/resume?reason={text}&taskHub={taskHub}&connection={connection}&code={systemKey}"
}

Webhook URL の形式は、実行するAzure Functions ホストのバージョンによって異なる場合があります。 上記の例は、Azure Functions 3.0 ホスト用です。

オーケストレーション インスタンスの HTTP 管理 Webhook URL を取得する

オーケストレーションに対するイベントを監視または発生させるには、外部システムを使用します。 外部システムは、HTTP API URL 検出で説明されている既定の応答の一部である webhook URL を介してDurable Functionsと通信します。 Webhook URL には、 オーケストレーション クライアント バインドを使用してプログラムでアクセスすることもできます。 具体的には、 HTTP 管理ペイロードの作成 API は、これらの Webhook URL を含むシリアル化可能なオブジェクトを取得します。

HTTP 管理ペイロードの作成 API には、次の 1 つのパラメーターがあります。

  • インスタンス ID: インスタンスの一意の ID。

メソッドは、次の文字列プロパティを持つオブジェクトを返します。

  • Id: オーケストレーションのインスタンス ID ( InstanceId 入力と同じである必要があります)。
  • StatusQueryGetUri: オーケストレーション インスタンスの状態 URL。
  • SendEventPostUri: オーケストレーション インスタンスの "イベントの発生" URL。
  • TerminatePostUri: オーケストレーション インスタンスの "terminate" URL。
  • PurgeHistoryDeleteUri: オーケストレーション インスタンスの "消去履歴" URL。
  • SuspendPostUri: オーケストレーション インスタンスの "一時停止" URL。
  • ResumePostUri: オーケストレーション インスタンスの "resume" URL。

関数は、次の例に示すように、これらのオブジェクトのインスタンスを外部システムに送信して、対応するオーケストレーションのイベントを監視または発生させます。

分離ワーカー モデル
[Function("SendInstanceInfo")]
[CosmosDBOutput(
    databaseName: "MonitorDB",
    containerName: "HttpManagementPayloads",
    Connection = "CosmosDBConnectionSetting")]
public static object SendInstanceInfo(
    [ActivityTrigger] TaskActivityContext context,
    [DurableClient] DurableTaskClient client)
{
    HttpManagementPayload payload = client.CreateHttpManagementPayload(context.InstanceId);

    // Send the payload to Azure Cosmos DB.
    return new { Payload = payload, id = context.InstanceId };
}

プロセス内モデル
[FunctionName("SendInstanceInfo")]
public static void SendInstanceInfo(
    [ActivityTrigger] IDurableActivityContext ctx,
    [DurableClient] IDurableOrchestrationClient client,
    [CosmosDB(
        databaseName: "MonitorDB",
        containerName: "HttpManagementPayloads",
        Connection = "CosmosDBConnectionSetting")]out dynamic document)
{
    HttpManagementPayload payload = client.CreateHttpManagementPayload(ctx.InstanceId);

    // send the payload to Azure Cosmos DB
    document = new { Payload = payload, id = ctx.InstanceId };
}

オーケストレーション インスタンスを巻き戻す

予期しない理由でオーケストレーションエラーが発生した場合は、その目的のために構築された API を使用して、インスタンスを以前は正常な状態に 巻き戻 します。

この API は、適切なエラー処理と再試行ポリシーに代わるものではありません。 代わりに、予期しない理由でオーケストレーション インスタンスが失敗した場合にのみ使用することを目的としています。 Failed以外の状態のオーケストレーション (RunningPendingTerminatedCompletedなど) は"巻き戻し" できません。 エラー処理と再試行ポリシーの詳細については、 エラー処理 に関する記事を参照してください。

オーケストレーションを RewindAsync 状態に戻すには、rewind (.NET) または (JavaScript) メソッドを使用します。 このメソッドは、オーケストレーションエラーの原因となったアクティビティまたはサブ割り当て実行エラーも再実行します。

たとえば、一連の 人間による承認を含むワークフローがあるとします。 承認が必要であることを他のユーザーに通知し、リアルタイムの応答を待機する一連のアクティビティ関数があるとします。 すべての承認アクティビティが応答またはタイムアウトを受け取った後、無効なデータベース 接続文字列など、アプリケーションの構成ミスが原因で別のアクティビティが失敗したとします。 その結果、ワークフローの深部でオーケストレーションエラーが発生します。 RewindAsync (.NET) または rewind (JavaScript) API を使用すると、アプリケーション管理者は構成エラーを修正し、失敗したオーケストレーションをエラーの直前の状態に戻すことができます。 人間とのやり取りの手順を再承認する必要はありません。これでオーケストレーションを正常に完了できます。

巻き戻し機能では、永続的タイマーを使用するオーケストレーション インスタンスの巻き戻しはサポートされていません。

分離ワーカー モデル
[Function("RewindInstance")]
public static Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("rewind-queue")] string instanceId)
{
    string reason = "Orchestrator failed and needs to be revived.";
    return client.RewindInstanceAsync(instanceId, reason);
}

プロセス内モデル
[FunctionName("RewindInstance")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("rewind-queue")] string instanceId)
{
    string reason = "Orchestrator failed and needs to be revived.";
    return client.RewindAsync(instanceId, reason);
}

using Microsoft.DurableTask.Client;

string reason = "Orchestrator failed and needs to be revived.";
await client.RewindInstanceAsync(instanceId, reason);

オーケストレーション インスタンスを再起動する

オーケストレーションを再起動すると、以前に実行されたインスタンスの履歴を使用して新しいインスタンスが作成されます。 この機能は、同じ入力とインスタンス ID パターンでオーケストレーションを再実行し、元のパターンに基づいて新しい実行を作成する場合に便利です。

分離ワーカー モデル
[Function("RestartInstance")]
public static Task<string?> Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("restart-queue")] string instanceId)
{
    return client.RestartAsync(instanceId, restartWithNewInstanceId: true);
}

プロセス内モデル
[FunctionName("RestartInstance")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("restart-queue")] string instanceId)
{
    return client.RestartAsync(instanceId, restartWithNewInstanceId: true);
}

using Microsoft.DurableTask.Client;

// Restart an orchestration with a new instance ID
string newInstanceId = await client.RestartInstanceAsync(instanceId, restartWithNewInstanceId: true);
Console.WriteLine($"Restarted as new instance: {newInstanceId}");

// Restart an orchestration keeping the same instance ID
await client.RestartInstanceAsync(instanceId, restartWithNewInstanceId: false);

オーケストレーション インスタンスの履歴を消去する

オーケストレーションに関連付けられているすべてのデータを削除するには、インスタンス履歴を消去します。 たとえば、完了したインスタンスに関連付けられているストレージ リソースを削除します。 オーケストレーション クライアントによって定義された消去インスタンス API を使用します。

次の例は、1 つのオーケストレーション インスタンスを消去する方法を示しています。

分離ワーカー モデル
[Function("PurgeInstanceHistory")]
public static async Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("purge-queue")] string instanceId)
{
    await client.PurgeInstanceAsync(instanceId);
}

プロセス内モデル
[FunctionName("PurgeInstanceHistory")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("purge-queue")] string instanceId)
{
    return client.PurgeInstanceHistoryAsync(instanceId);
}

using Microsoft.DurableTask.Client;

// Purge a single orchestration instance
PurgeResult result = await client.PurgeInstanceAsync(instanceId);
Console.WriteLine($"Purged {result.PurgedInstanceCount} instance(s).");

次の例は、指定した時間間隔後に完了したすべてのオーケストレーション インスタンスの履歴を消去するタイマーによってトリガーされる関数を示しています。 この場合、30 日以上前に完了したすべてのインスタンスのデータが削除されます。 この関数例は、1 日に 1 回、午後 12 時 (UTC) に実行するようにスケジュールされています。

分離ワーカー モデル
[Function("PurgeInstanceHistory")]
public static async Task Run(
    [DurableClient] DurableTaskClient client,
    [TimerTrigger("0 0 12 * * *")] TimerInfo myTimer)
{
    var filter = new PurgeInstancesFilter(
        CreatedFrom: DateTime.MinValue,
        CreatedTo: DateTime.UtcNow.AddDays(-30),
        Statuses: new[] { OrchestrationRuntimeStatus.Completed });

    await client.PurgeAllInstancesAsync(filter);
}

プロセス内モデル
[FunctionName("PurgeInstanceHistory")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [TimerTrigger("0 0 12 * * *")] TimerInfo myTimer)
{
    return client.PurgeInstanceHistoryAsync(
        DateTime.MinValue,
        DateTime.UtcNow.AddDays(-30),  
        new List<OrchestrationStatus>
        {
            OrchestrationStatus.Completed
        });
}

using Microsoft.DurableTask.Client;

// Purge completed instances older than 30 days
var filter = new PurgeInstancesFilter(
    CreatedFrom: DateTime.MinValue,
    CreatedTo: DateTime.UtcNow.AddDays(-30),
    Statuses: new[] { OrchestrationRuntimeStatus.Completed });

PurgeResult result = await client.PurgeAllInstancesAsync(filter);
Console.WriteLine($"Purged {result.PurgedInstanceCount} instance(s).");

消去履歴操作を成功させるには、ターゲット インスタンスのランタイム状態が [完了]、[ 終了]、または [失敗] である必要があります。

次のステップ