オーケストレーションのパターンOrchestration patterns

Durable Functions を使用すると、サーバーレス環境で、実行時間の長い個別のアクティビティで構成されるステートフル ワークフローを簡単に作成できます。Durable Functions makes it easier to create stateful workflows that are composed of discrete, long running activities in a serverless environment. Durable Functions ではワークフローの進行状況を追跡でき、実行履歴が定期的にチェックポイント処理されるため、いくつかの興味深いパターンを実装するのに役立ちます。Since Durable Functions can track the progress of your workflows and periodically checkpoints the execution history, it lends itself to implementing some interesting patterns.

関数チェーンFunction chaining

一般的な連続プロセスでは、アクティビティを特定の順序で 1 つずつ実行する必要があります。In a typical sequential process, activities need to execute one after the other in a particular order. 必要に応じて、次回のアクティビティで、前の関数からの出力が必要になる場合があります。Optionally, the upcoming activity may require some output from the previous function. このようにアクティビティの順序に依存することで、実行の関数チェーンが作成されます。This dependency on the ordering of activities creates a function chain of execution.

Durable Functions を使用してこのワークフロー パターンを実装する利点は、チェックポイント処理を実行できることにあります。The benefit of using Durable Functions to implement this workflow pattern comes from its ability to do checkpointing. サーバーがクラッシュした場合、ネットワークがタイムアウトした場合、またはその他の問題が発生した場合、Durable Functions では、別のサーバー上にある場合でも最後の既知の状態から再開し、ワークフローの実行を継続することができます。If the server crashes, the network times out or some other issue occurs, Durable functions can resume from the last known state and continue running your workflow even if it's on another server.

[FunctionName("PlaceOrder")]
public static async Task<string> PlaceOrder([OrchestrationTrigger] DurableOrchestrationContext context)
{
    OrderRequestData orderData = context.GetInput<OrderRequestData>();

    await context.CallActivityAsync<bool>("CheckAndReserveInventory", orderData);
    await context.CallActivityAsync<bool>("ProcessPayment", orderData);

    string trackingNumber = await context.CallActivityAsync<string>("ScheduleShipping", orderData);
    await context.CallActivityAsync<string>("EmailCustomer", trackingNumber);

    return trackingNumber;
}

前のコード サンプルでは、CallActivityAsync 関数により、データ センター内の仮想マシンで特定のアクティビティが実行されます。In the preceding code sample, the CallActivityAsync function is responsible for running a given activity on a virtual machine in the data center. await が返され、基になるタスクが完了すると、実行が履歴テーブルに記録されます。When the await returns and the underlying Task completes, the execution will be recorded to the history table. オーケストレーター関数のコードでは、タスク並列ライブラリの任意の使い慣れた構造と async/await キーワードを利用できます。The code in the orchestrator function can make use of any of the familiar constructs of the Task Parallel Library and the async/await keywords.

次のコードは、ProcessPayment メソッドがどのようになるかを示す簡単な例です。The following code is a simplified example of what the ProcessPayment method may look like:

[FunctionName("ProcessPayment")]
public static bool ProcessPayment([ActivityTrigger] DurableActivityContext context)
{
    OrderRequestData orderData = context.GetInput<OrderRequestData>();

    ApplyCoupons(orderData);
    if(IssuePaymentRequest(orderData)) {
        return true;
    }

    return false;
}

非同期 HTTP APIAsynchronous HTTP APIs

場合によっては、ワークフローに含まれるアクティビティが、完了するのに比較的長い時間がかかることがあります。In some cases, workflows may contain activities that take a relatively long period of time to complete. BLOB ストレージへのメディア ファイルのバックアップを開始するプロセスを考えてみましょう。Imagine a process that kicks off the backup of media files into blob storage. メディア ファイルのサイズと数によっては、このバックアップ プロセスが完了するまでに数時間かかることがあります。Depending on the size and quantity of the media files, this backup process may take hours to complete.

このシナリオでは、実行中のワークフローの状態を確認する DurableOrchestrationClient の機能が有用になります。In this scenario, the DurableOrchestrationClient's ability to check the status of a running workflow becomes useful. HttpTrigger を使用してワークフローを開始する場合は、CreateCheckStatusResponse メソッドを使用して HttpResponseMessageのインスタンスを返すことができます。When using an HttpTrigger to start a workflow, the CreateCheckStatusResponse method can be used to return an instance of HttpResponseMessage. この応答により、実行中のプロセスの状態を確認するために使用できるペイロードの URI がクライアントに提供されます。This response provides the client with a URI in the payload that can be used to check the status of the running process.

[FunctionName("OrderWorkflow")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Function, "POST")]HttpRequestMessage req,
    [OrchestrationClient ] DurableOrchestrationClient orchestrationClient)
{
    OrderRequestData data = await req.Content.ReadAsAsync<OrderRequestData>();

    string instanceId = await orchestrationClient.StartNewAsync("PlaceOrder", data);

    return orchestrationClient.CreateCheckStatusResponse(req, instanceId);
}

次のサンプル結果は、応答ペイロードの構造を示しています。The sample result below shows the structure of the response payload.

{
    "id": "instanceId",
    "statusQueryGetUri": "http://host/statusUri",
    "sendEventPostUri": "http://host/eventUri",
    "terminatePostUri": "http://host/terminateUri"
}

任意の HTTP クライアントを使用して、statusQueryGetUri の URI に対して GET 要求を作成し、実行中のワークフローの状態を調べることができます。Using your preferred HTTP client, GET requests can be made to the URI in statusQueryGetUri to inspect the status of the running workflow. 返される状態の応答は、次のコードのようになります。The returned status response should resemble the following code.

{
    "runtimeStatus": "Running",
    "input": {
        "$type": "DurableFunctionsDemos.OrderRequestData, DurableFunctionsDemos"
    },
    "output": null,
    "createdTime": "2018-01-01T00:22:05Z",
    "lastUpdatedTime": "2018-01-01T00:22:09Z"
}

プロセスが続行されると、状態の応答は Failed または Completed に変わります。As the process continues, the status response will change to either Failed or Completed. 正常に完了した場合、ペイロード内の output プロパティには、返されたデータがすべて含まれます。On successful completion, the output property in the payload will contain any returned data.

監視Monitoring

単純な定期的なタスクの場合、Azure Functions では、CRON 式に基づいてスケジュールできる TimerTrigger が提供されます。For simple recurring tasks, Azure Functions provides the TimerTrigger that can be scheduled based on a CRON expression. タイマーは、単純で短時間のタスクには適していますが、より柔軟なスケジュール設定が必要なシナリオもあります。The timer works well for simple, short-lived tasks, but there might be scenarios where more flexible scheduling is needed. このようなシナリオでは、監視パターンと Durable Functions が役に立ちます。This scenario is when the monitoring pattern and Durable Functions can help.

Durable Functions では、柔軟なスケジュール設定間隔と有効期間の管理を実現できるほか、1 つのオーケストレーション関数から複数の監視プロセスを作成できます。Durable Functions allows for flexible scheduling intervals, lifetime management, and the creation of multiple monitor processes from a single orchestration function. この機能のユース ケースの 1 つとして、特定のしきい値が満たされると完了する株価の変動に対してウォッチャーを作成することが考えられます。One use case for this functionality might be to create watchers for stock price changes that complete once a certain threshold is met.

[FunctionName("CheckStockPrice")]
public static async Task CheckStockPrice([OrchestrationTrigger] DurableOrchestrationContext context)
{
    StockWatcherInfo stockInfo = context.GetInput<StockWatcherInfo>();
    const int checkIntervalSeconds = 120;
    StockPrice initialStockPrice = null;

    DateTime fireAt;
    DateTime exitTime = context.CurrentUtcDateTime.Add(stockInfo.TimeLimit);

    while (context.CurrentUtcDateTime < exitTime)
    {
        StockPrice currentStockPrice = await context.CallActivityAsync<StockPrice>("GetStockPrice", stockInfo);

        if (initialStockPrice == null)
        {
            initialStockPrice = currentStockPrice;
            fireAt = context.CurrentUtcDateTime.AddSeconds(checkIntervalSeconds);
            await context.CreateTimer(fireAt, CancellationToken.None);
            continue;
        }

        decimal percentageChange = (initialStockPrice.Price - currentStockPrice.Price) /
                               ((initialStockPrice.Price + currentStockPrice.Price) / 2);

        if (Math.Abs(percentageChange) >= stockInfo.PercentageChange)
        {
            // Change threshold detected
            await context.CallActivityAsync("NotifyStockPercentageChange", currentStockPrice);
            break;
        }

        // Sleep til next polling interval
        fireAt = context.CurrentUtcDateTime.AddSeconds(checkIntervalSeconds);
        await context.CreateTimer(fireAt, CancellationToken.None);
    }
}

DurableOrchestrationContextCreateTimer メソッドにより、株価の変動を確認するために、ループの次回の呼び出しのスケジュールが設定されます。DurableOrchestrationContext's CreateTimer method sets up the schedule for the next invocation of the loop to check for stock price changes. DurableOrchestrationContext には、現在の DateTime 値 (UTC) を取得するための CurrentUtcDateTime プロパティも含まれます。DurableOrchestrationContext also has a CurrentUtcDateTime property to get the current DateTime value in UTC. テスト用に簡単にモックできるため、DateTime.UtcNow の代わりにこのプロパティを使用することをお勧めします。It's better to use this property instead of DateTime.UtcNow because it's easily mocked for testing.