Durable Functions の概要Durable Functions overview

Durable Functions は、サーバーレス環境でステートフル関数を記述できる、Azure FunctionsAzure WebJobs の拡張機能です。Durable Functions is an extension of Azure Functions and Azure WebJobs that lets you write stateful functions in a serverless environment. この拡張機能は状態、チェックポイント、再起動を管理します。The extension manages state, checkpoints, and restarts for you.

この拡張機能を使用すると、オーケストレーター関数という新しいタイプの関数で、ステートフルなワークフローを定義できます。The extension lets you define stateful workflows in a new type of function called an orchestrator function. オーケストレーター関数のメリットは以下のとおりです。Here are some of the advantages of orchestrator functions:

  • コードでワークフローを定義します。They define workflows in code. JSON スキーマまたはデザイナーが不要です。No JSON schemas or designers are needed.
  • 他の関数を同期と非同期のどちらでも呼び出すことができます。They can call other functions synchronously and asynchronously. 呼び出された関数からの出力は、ローカル変数に保存できます。Output from called functions can be saved to local variables.
  • 関数が待機するたびに、自動で進行状況にチェックポイントを設定します。They automatically checkpoint their progress whenever the function awaits. プロセスがリサイクルされるか VM が再起動される場合に、ローカルの状態が失われません。Local state is never lost if the process recycles or the VM reboots.

注意

Durable Functions は Azure Functions の高度な拡張機能であり、すべてのアプリケーションに適しているわけではありません。Durable Functions is an advanced extension for Azure Functions that is not appropriate for all applications. この記事は、開発者が Azure Functions のコンセプトを十分に理解しており、サーバーレス アプリケーションの開発に取り組んでいることを前提としています。The rest of this article assumes that you have a strong familiarity with Azure Functions concepts and the challenges involved in serverless application development.

Durable Functions の主な用途は、サーバーレス アプリケーションにおける複雑でステートフルな調整の問題をシンプルにすることです。The primary use case for Durable Functions is simplifying complex, stateful coordination problems in serverless applications. 次のセクションでは、Durable Functions を使用することでメリットがある、いくつかの典型的なアプリケーションのパターンを示します。The following sections describe some typical application patterns that can benefit from Durable Functions.

パターン #1: 関数チェーンPattern #1: Function chaining

関数チェーンは、特定の順序で関数のシーケンスを実行するパターンです。Function chaining refers to the pattern of executing a sequence of functions in a particular order. ある関数の出力が、別の関数の入力に適用される必要がある、ということがよくあります。Often the output of one function needs to be applied to the input of another function.

関数チェーンの図

Durable Functions を使用すれば、このパターンをコードで簡潔に実装できます。Durable Functions allows you to implement this pattern concisely in code.

C#C#

public static async Task<object> Run(DurableOrchestrationContext ctx)
{
    try
    {
        var x = await ctx.CallActivityAsync<object>("F1");
        var y = await ctx.CallActivityAsync<object>("F2", x);
        var z = await ctx.CallActivityAsync<object>("F3", y);
        return  await ctx.CallActivityAsync<object>("F4", z);
    }
    catch (Exception)
    {
        // error handling/compensation goes here
    }
}

JavaScript (Functions v2 のみ)JavaScript (Functions v2 only)

const df = require("durable-functions");

module.exports = df(function*(ctx) {
    const x = yield ctx.df.callActivityAsync("F1");
    const y = yield ctx.df.callActivityAsync("F2", x);
    const z = yield ctx.df.callActivityAsync("F3", y);
    return yield ctx.df.callActivityAsync("F4", z);
});

"F1"、"F2"、"F3"、"F4" という値は、関数アプリ内の他の関数の名前です。The values "F1", "F2", "F3", and "F4" are the names of other functions in the function app. 制御フローは、通常の命令型のコーディング構造で実装されます。Control flow is implemented using normal imperative coding constructs. つまり、コードは上から下へ実行され、コードに条件文やループなどの既存言語の制御フロー セマンティクスを含めることができます。That is, code executes top-down and can involve existing language control flow semantics, like conditionals, and loops. エラー処理ロジックを try ブロック、catch ブロック、finally ブロックに含めることもできます。Error handling logic can be included in try/catch/finally blocks.

ctx パラメーター (DurableOrchestrationContext) は名前によって他の関数を呼び出し、パラメーターを渡して、関数の出力を返すメソッドを提供します。The ctx parameter (DurableOrchestrationContext) provides methods for invoking other functions by name, passing parameters, and returning function output. コードが await を呼び出すたびに Durable Functions フレームワークは、現在の関数インスタンスの進行状況にチェックポイントを設定します。Each time the code calls await, the Durable Functions framework checkpoints the progress of the current function instance. プロセスまたは VM が実行途中でリサイクルされる場合、その関数インスタンスは先の await 呼び出しから再開されます。If the process or VM recycles midway through the execution, the function instance resumes from the previous await call. この再起動動作については、後で詳しく説明します。More on this restart behavior later.

パターン #2: ファンアウト/ファンインPattern #2: Fan-out/fan-in

ファンアウト/ファンインは、複数の関数を並列に実行してすべてが完了するまで待機するパターンです。Fan-out/fan-in refers to the pattern of executing multiple functions in parallel, and then waiting for all to finish. 複数の関数から返された結果に基づいて集計作業が行われる場合があります。Often some aggregation work is done on results returned from the functions.

ファンアウト/ファンインの図

通常の関数では、関数が複数のメッセージを 1 つのキューに送信することでファンアウトが行われます。With normal functions, fanning out can be done by having the function send multiple messages to a queue. しかし、ファンインして戻すことはこれよりずっと難しくなります。However, fanning back in is much more challenging. キューによってトリガーされる関数が終了し、関数の出力が格納される時間を追跡するように、コードを記述する必要があります。You'd have to write code to track when the queue-triggered functions end and store function outputs. Durable Functions 拡張機能は、比較的単純なコードでこのパターンを処理します。The Durable Functions extension handles this pattern with relatively simple code.

C#C#

public static async Task Run(DurableOrchestrationContext ctx)
{
    var parallelTasks = new List<Task<int>>();

    // get a list of N work items to process in parallel
    object[] workBatch = await ctx.CallActivityAsync<object[]>("F1");
    for (int i = 0; i < workBatch.Length; i++)
    {
        Task<int> task = ctx.CallActivityAsync<int>("F2", workBatch[i]);
        parallelTasks.Add(task);
    }

    await Task.WhenAll(parallelTasks);

    // aggregate all N outputs and send result to F3
    int sum = parallelTasks.Sum(t => t.Result);
    await ctx.CallActivityAsync("F3", sum);
}

JavaScript (Functions v2 のみ)JavaScript (Functions v2 only)

const df = require("durable-functions");

module.exports = df(function*(ctx) {
    const parallelTasks = [];

    // get a list of N work items to process in parallel
    const workBatch = yield ctx.df.callActivityAsync("F1");
    for (let i = 0; i < workBatch.length; i++) {
        parallelTasks.push(ctx.df.callActivityAsync("F2", workBatch[i]));
    }

    yield ctx.df.task.all(parallelTasks);

    // aggregate all N outputs and send result to F3
    const sum = parallelTasks.reduce((prev, curr) => prev + curr, 0);
    yield ctx.df.callActivityAsync("F3", sum);
});

ファンアウト作業が F2 関数の複数のインスタンスに配分され、タスクの動的リストを使用してこの作業が追跡されます。The fan-out work is distributed to multiple instances of function F2, and the work is tracked by using a dynamic list of tasks. .NET Task.WhenAll API が呼び出され、すべての呼び出された関数が終了するまで待機します。The .NET Task.WhenAll API is called to wait for all of the called functions to finish. 次に、F2 関数の出力が動的なタスク リストから集計されて、F3 関数に渡されます。Then the F2function outputs are aggregated from the dynamic task list and passed on to the F3 function.

Task.WhenAllawait 呼び出しの際に自動でチェックポイントを設定することで、実行途中でクラッシュや再起動が生じても既に完了したすべてのタスクをやり直す必要がなくなります。The automatic checkpointing that happens at the await call on Task.WhenAll ensures that any crash or reboot midway through does not require a restart of any already completed tasks.

パターン #3: 非同期 HTTP APIPattern #3: Async HTTP APIs

3 番目のパターンでもっとも重要なのは、外部クライアントとの間で行われる実行時間の長い操作の状態を調整するという問題です。The third pattern is all about the problem of coordinating the state of long-running operations with external clients. このパターンを実装する一般的な方法は、HTTP 呼び出しにより実行時間の長い操作をトリガーし、その操作が完了する時間を照会できる状態エンドポイントにクライアントをリダイレクトするという方法です。A common way to implement this pattern is by having the long-running action triggered by an HTTP call, and then redirecting the client to a status endpoint that they can poll to learn when the operation completes.

HTTP API の図

Durable Functions は、実行時間の長い関数を操作するコードをシンプルにするビルトイン API を提供します。Durable Functions provides built-in APIs that simplify the code you write for interacting with long-running function executions. サンプルでは、新しいオーケストレーター関数のインスタンスを開始するために使用できる、シンプルな REST コマンドについて説明しています。The samples show a simple REST command that can be used to start new orchestrator function instances. インスタンスが開始されると、この拡張機能はオーケストレーター関数の状態をクエリする Webhook HTTP API を公開します。Once an instance is started, the extension exposes webhook HTTP APIs that query the orchestrator function status. 次の例では、オーケストレーターを開始してその状態をクエリする REST コマンドを示します。The following example shows the REST commands to start an orchestrator and to query its status. わかりやすくするため、この例では細部をいくらか省略しています。For clarity, some details are omitted from the example.

> curl -X POST https://myfunc.azurewebsites.net/orchestrators/DoWork -H "Content-Length: 0" -i
HTTP/1.1 202 Accepted
Content-Type: application/json
Location: https://myfunc.azurewebsites.net/admin/extensions/DurableTaskExtension/b79baf67f717453ca9e86c5da21e03ec

{"id":"b79baf67f717453ca9e86c5da21e03ec", ...}

> curl https://myfunc.azurewebsites.net/admin/extensions/DurableTaskExtension/b79baf67f717453ca9e86c5da21e03ec -i
HTTP/1.1 202 Accepted
Content-Type: application/json
Location: https://myfunc.azurewebsites.net/admin/extensions/DurableTaskExtension/b79baf67f717453ca9e86c5da21e03ec

{"runtimeStatus":"Running","lastUpdatedTime":"2017-03-16T21:20:47Z", ...}

> curl https://myfunc.azurewebsites.net/admin/extensions/DurableTaskExtension/b79baf67f717453ca9e86c5da21e03ec -i
HTTP/1.1 200 OK
Content-Length: 175
Content-Type: application/json

{"runtimeStatus":"Completed","lastUpdatedTime":"2017-03-16T21:20:57Z", ...}

状態は Durable Functions ランタイムによって管理されるため、独自の状態追跡メカニズムを実装する必要はありません。Because the state is managed by the Durable Functions runtime, you don't have to implement your own status tracking mechanism.

Durable Functions 拡張機能には実行時間の長いオーケストレーションを管理するためのビルトイン Webhook がありますが、独自の関数トリガー (HTTP、キュー、またはイベント ハブなど) と orchestrationClient バインドを使用してこのパターンを自分で実装できます。Even though the Durable Functions extension has built-in webhooks for managing long-running orchestrations, you can implement this pattern yourself using your own function triggers (such as HTTP, queue, or Event Hub) and the orchestrationClient binding. たとえば、キュー メッセージを使用して終了をトリガーできます。For example, you could use a queue message to trigger termination. または、生成されたキーを認証で使用するビルトイン Webhook の代わりに、Azure Active Directory の認証ポリシーで保護された HTTP トリガーを使用できます。Or you could use an HTTP trigger protected by an Azure Active Directory authentication policy instead of the built-in webhooks that use a generated key for authentication.

// HTTP-triggered function to start a new orchestrator function instance.
public static async Task<HttpResponseMessage> Run(
    HttpRequestMessage req,
    DurableOrchestrationClient starter,
    string functionName,
    TraceWriter log)
{
    // Function name comes from the request URL.
    // Function input comes from the request content.
    dynamic eventData = await req.Content.ReadAsAsync<object>();
    string instanceId = await starter.StartNewAsync(functionName, eventData);

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

    return starter.CreateCheckStatusResponse(req, instanceId);
}

DurableOrchestrationClient starterパラメーターは、Durable Functions 拡張機能の一部である orchestrationClient 出力バインドからの値です。The DurableOrchestrationClient starter parameter is a value from the orchestrationClient output binding, which is part of the Durable Functions extension. このパラメーターは、新しいまたは既存のオーケストレーター関数インスタンスの開始や終了、インスタンスへのイベント送信やクエリ送信のためのメソッドを提供します。It provides methods for starting, sending events to, terminating, and querying for new or existing orchestrator function instances. 上記の例では、HTTP によってトリガーされる関数は受信 URL から functionName 値を受け取り、その値を StartNewAsync に渡します。In the previous example, an HTTP triggered-function takes in a functionName value from the incoming URL and passes that value to StartNewAsync. 次にこのバインド API は、Location ヘッダーとともに、開始されたインスタンスの状態を後で調べるため、またはインスタンスを終了するために使用するインスタンスの追加情報を含めた応答を返します。This binding API then returns a response that contains a Location header and additional information about the instance that can later be used to look up the status of the started instance or terminate it.

パターン 4: 監視Pattern #4: Monitoring

モニター パターンは、ワークフローの柔軟な "繰り返し" プロセスを参照します。たとえば、特定の条件が満たされるまでポーリングします。The monitor pattern refers to a flexible recurring process in a workflow - for example, polling until certain conditions are met. 通常のタイマー トリガーは、定期的なクリーンアップ ジョブなどの単純なシナリオに対処できますが、その間隔は静的であり、インスタンスの有効期間の管理は複雑になります。A regular timer-trigger can address a simple scenario, such as a periodic cleanup job, but its interval is static and managing instance lifetimes becomes complex. Durable Functions では、柔軟な繰り返し間隔とタスクの有効期間の管理を実行でき、1 つのオーケストレーションから複数のモニター プロセスを作成する機能も備えています。Durable Functions enables flexible recurrence intervals, task lifetime management, and the ability to create multiple monitor processes from a single orchestration.

例として、前述の非同期 HTTP API のシナリオの逆があります。An example would be reversing the earlier async HTTP API scenario. 外部クライアントのエンドポイントを公開して実行時間の長い操作を監視する代わりに、長時間実行されるモニターで、外部エンドポイントを使用して、何らかの状態変更が発生するまで待機します。Instead of exposing an endpoint for an external client to monitor a long-running operation, the long-running monitor consumes an external endpoint, waiting for some state change.

モニター ダイアグラム

Durable Functions を使用して、任意のエンドポイントを観察する複数のモニターを、数行のコードで作成できます。Using Durable Functions, multiple monitors that observe arbitrary endpoints can be created in a few lines of code. モニターは、何らかの条件が満たされた場合、または DurableOrchestrationClient によって実行を終了でき、待機間隔は、何らかの条件に基づいて変更できます (つまり指数バックオフを実装します)。次のコードは、基本的なモニターを実装します。The monitors can end execution when some condition is met, or be terminated by the DurableOrchestrationClient, and their wait interval can be changed based on some condition (i.e. exponential backoff.) The following code implements a basic monitor.

C#C#

public static async Task Run(DurableOrchestrationContext ctx)
{
    int jobId = ctx.GetInput<int>();
    int pollingInterval = GetPollingInterval();
    DateTime expiryTime = GetExpiryTime();

    while (ctx.CurrentUtcDateTime < expiryTime) 
    {
        var jobStatus = await ctx.CallActivityAsync<string>("GetJobStatus", jobId);
        if (jobStatus == "Completed")
        {
            // Perform action when condition met
            await ctx.CallActivityAsync("SendAlert", machineId);
            break;
        }

        // Orchestration will sleep until this time
        var nextCheck = ctx.CurrentUtcDateTime.AddSeconds(pollingInterval);
        await ctx.CreateTimer(nextCheck, CancellationToken.None);
    }

    // Perform further work here, or let the orchestration end
}

JavaScript (Functions v2 のみ)JavaScript (Functions v2 only)

const df = require("durable-functions");
const df = require("moment");

module.exports = df(function*(ctx) {
    const jobId = ctx.df.getInput();
    const pollingInternal = getPollingInterval();
    const expiryTime = getExpiryTime();

    while (moment.utc(ctx.df.currentUtcDateTime).isBefore(expiryTime)) {
        const jobStatus = yield ctx.df.callActivityAsync("GetJobStatus", jobId);
        if (jobStatus === "Completed") {
            // Perform action when condition met
            yield ctx.df.callActivityAsync("SendAlert", machineId);
            break;
        }

        // Orchestration will sleep until this time
        const nextCheck = moment.utc(ctx.df.currentUtcDateTime).add(pollingInterval, 's');
        yield ctx.df.createTimer(nextCheck.toDate());
    }

    // Perform further work here, or let the orchestration end
});

要求が受信されると、そのジョブ ID 用の新しいオーケストレーション インスタンスが作成されます。When a request is received, a new orchestration instance is created for that job ID. インスタンスは、条件が満たされてループが終了するまで、状態をポーリングします。The instance polls a status until a condition is met and the loop is exited. ポーリング間隔を制御するために永続的タイマーが使用されます。A durable timer is used to control the polling interval. さらに作業を実行するか、オーケストレーションを終了できます。Further work can then be performed, or the orchestration can end. ctx.CurrentUtcDateTimeexpiryTime を超えると、モニターが終了します。When the ctx.CurrentUtcDateTime exceeds the expiryTime, the monitor ends.

パターン #5: 人による操作Pattern #5: Human interaction

ほとんどのプロセスには、何らかの人による操作が含まれます。Many processes involve some kind of human interaction. 自動化されたプロセスに人による操作が含まれる場合に問題になるのが、人は必ずしもクラウド サービスのように可用性と応答性が高くないということです。The tricky thing about involving humans in an automated process is that people are not always as highly available and responsive as cloud services. 自動化されたプロセスはこのことを許容する必要があり、通常タイムアウトや補正ロジックを使用してそれを行います。Automated processes must allow for this, and they often do so by using timeouts and compensation logic.

人による操作を含むビジネス プロセスの一例として、承認プロセスがあります。One example of a business process that involves human interaction is an approval process. たとえば、特定の額を超えた経費報告書について上司から承認を得る必要があるなどの場合です。For example, approval from a manager might be required for an expense report that exceeds a certain amount. 72 時間以内に上司が承認しない (上司が休暇に入ったなどの) 場合に、他の誰か (おそらくは上司の上司) から承認を得るためにエスカレーション プロセスに入ります。If the manager does not approve within 72 hours (maybe they went on vacation), an escalation process kicks in to get the approval from someone else (perhaps the manager's manager).

人による操作の図

このパターンは、オーケストレーター関数を使用して実装できます。This pattern can be implemented using an orchestrator function. オーケストレーターは、永続タイマーを使用して承認を要求し、タイムアウトした場合にエスカレーションします。The orchestrator would use a durable timer to request approval and escalate in case of timeout. また、人による何らかの操作によって生成された通知である外部イベントを待機します。It would wait for an external event, which would be the notification generated by some human interaction.

C#C#

public static async Task Run(DurableOrchestrationContext ctx)
{
    await ctx.CallActivityAsync("RequestApproval");
    using (var timeoutCts = new CancellationTokenSource())
    {
        DateTime dueTime = ctx.CurrentUtcDateTime.AddHours(72);
        Task durableTimeout = ctx.CreateTimer(dueTime, timeoutCts.Token);

        Task<bool> approvalEvent = ctx.WaitForExternalEvent<bool>("ApprovalEvent");
        if (approvalEvent == await Task.WhenAny(approvalEvent, durableTimeout))
        {
            timeoutCts.Cancel();
            await ctx.CallActivityAsync("ProcessApproval", approvalEvent.Result);
        }
        else
        {
            await ctx.CallActivityAsync("Escalate");
        }
    }
}

JavaScript (Functions v2 のみ)JavaScript (Functions v2 only)

const df = require("durable-functions");
const df = require('moment');

module.exports = df(function*(ctx) {
    yield ctx.df.callActivityAsync("RequestApproval");

    const dueTime = moment.utc(ctx.df.currentUtcDateTime).add(72, 'h');
    const durableTimeout = ctx.df.createTimer(dueTime.toDate());

    const approvalEvent = ctx.df.waitForExternalEvent("ApprovalEvent");
    if (approvalEvent === yield ctx.df.Task.any([approvalEvent, durableTimeout])) {
        durableTimeout.cancel();
        yield ctx.df.callActivityAsync("ProcessApproval", approvalEvent.result);
    } else {
        yield ctx.df.callActivityAsync("Escalate");
    }
});

永続タイマーは ctx.CreateTimer を呼び出すことで作成されます。The durable timer is created by calling ctx.CreateTimer. 通知は ctx.WaitForExternalEvent が受け取ります。The notification is received by ctx.WaitForExternalEvent. そして、エスカレーションする (最初にタイムアウトが発生する) か、承認を処理する (タイムアウト前に承認を得る) かを決定するために Task.WhenAny が呼び出されます。And Task.WhenAny is called to decide whether to escalate (timeout happens first) or process approval (approval is received before timeout).

外部クライアントは、組み込みの HTTP API を使用するか、別の関数の DurableOrchestrationClient.RaiseEventAsync API を使用して、待機中のオーケストレーター関数にイベント通知を配信できます。An external client can deliver the event notification to a waiting orchestrator function using either the built-in HTTP APIs or by using DurableOrchestrationClient.RaiseEventAsync API from another function:

public static async Task Run(string instanceId, DurableOrchestrationClient client)
{
    bool isApproved = true;
    await client.RaiseEventAsync(instanceId, "ApprovalEvent", isApproved);
}

テクノロジThe technology

背後では、永続的タスクのオーケストレーションを構築するための GitHub のオープン ソース ライブラリである Durable Task Framework の上に、Durable Functions 拡張機能が構築されています。Behind the scenes, the Durable Functions extension is built on top of the Durable Task Framework, an open-source library on GitHub for building durable task orchestrations. Azure Functions が Azure WebJobs のサーバーレスな進化形であるのと同じように、Durable Functions は Durable Task Framework のサーバーレスな進化形です。Much like how Azure Functions is the serverless evolution of Azure WebJobs, Durable Functions is the serverless evolution of the Durable Task Framework. Durable Task Framework は、ミッション クリティカルなプロセスを自動化するために Microsoft 内外で頻繁に使用されています。The Durable Task Framework is used heavily within Microsoft and outside as well to automate mission-critical processes. サーバーレスな Azure Functions 環境には自然に適合します。It's a natural fit for the serverless Azure Functions environment.

イベント ソーシング、チェックポイント設定、リプレイEvent sourcing, checkpointing, and replay

オーケストレーター関数は、Event Sourcing として知られるクラウド デザイン パターンを使用して、この関数の実行状態を安定的に維持します。Orchestrator functions reliably maintain their execution state using a cloud design pattern known as Event Sourcing. オーケストレーションの "現在の" 状態を直接格納する代わりに、この永続的な拡張機能は追加専用のストアを使用して、関数オーケストレーションがとる "アクションのすべて" を記録します。Instead of directly storing the current state of an orchestration, the durable extension uses an append-only store to record the full series of actions taken by the function orchestration. これには、ランタイムの完全な状態を "ダンプする" のと比べて、パフォーマンス、スケーラビリティ、応答時間の改善など多くのメリットがあります。This has many benefits, including improving performance, scalability, and responsiveness compared to "dumping" the full runtime state. 他にも、トランザクション データに最終的な一貫性を提供する、完全な監査証跡や監査履歴を維持するなどのメリットもあります。Other benefits include providing eventual consistency for transactional data and maintaining full audit trails and history. 監査証跡のみで、信頼性の高い補正アクションが可能です。The audit trails themselves enable reliable compensating actions.

この拡張機能による Event Sourcing の使用は透過的です。The use of Event Sourcing by this extension is transparent. 背後では、オーケストレーター関数内の await 演算子が、Durable Task Framework のディスパッチャーにオーケストレーター スレッドのコントロールを引き渡します。Under the covers, the await operator in an orchestrator function yields control of the orchestrator thread back to the Durable Task Framework dispatcher. 次に、このディスパッチャーは、オーケストレーター関数がスケジュールした新しいアクション (1 つ以上の子関数を呼び出す、永続タイマーをスケジュールする、など) をストレージにコミットします。The dispatcher then commits any new actions that the orchestrator function scheduled (such as calling one or more child functions or scheduling a durable timer) to storage. この透過的なコミット アクションは、オーケストレーション インスタンスの "実行履歴" に追加されます。This transparent commit action appends to the execution history of the orchestration instance. この履歴はストレージ テーブルに格納されます。The history is stored in a storage table. 次に、このコミット アクションはキューにメッセージを追加して実際の作業をスケジュールします。The commit action then adds messages to a queue to schedule the actual work. この時点では、メモリからオーケストレーター関数をアンロードできます。At this point, the orchestrator function can be unloaded from memory. それに対する課金は Azure Functions の従量課金プランを使用している場合は停止します。Billing for it stops if you're using the Azure Functions Consumption Plan. 処理すべき作業がさらにある場合は、関数は再起動され、関数の状態は再構築されます。When there is more work to do, the function is restarted and its state is reconstructed.

オーケストレーション関数にさらに処理すべき作業が与えられる (たとえば、応答メッセージを受け取る、または永続タイマーが期限切れになる) と、ローカルの状態を再構築するためにオーケストレーターがもう一度起動して始めからその関数全体を再実行します。Once an orchestration function is given more work to do (for example, a response message is received or a durable timer expires), the orchestrator wakes up again and re-executes the entire function from the start in order to rebuild the local state. このリプレイ中にコードが関数を呼び出そうとする (または他の非同期作業を行おうとする) と、Durable Task Framework は現在のオーケストレーションの実行履歴を照会します。If during this replay the code tries to call a function (or do any other async work), the Durable Task Framework consults with the execution history of the current orchestration. アクティビティ関数が既に実行されいくつかの結果を生成していることが確認されると、その関数の結果をリプレイしてオーケストレーター コードが実行を継続します。If it finds that the activity function has already executed and yielded some result, it replays that function's result, and the orchestrator code continues running. この動作は、関数コードが完了する、または新しい非同期作業をスケジュールする時点まで継続して行われます。This continues happening until the function code gets to a point where either it is finished or it has scheduled new async work.

オーケストレーター コードの制約Orchestrator code constraints

このリプレイ動作は、オーケストレーター関数に記述できるコード タイプに関する制約を設けます。The replay behavior creates constraints on the type of code that can be written in an orchestrator function. たとえば、オーケストレーター コードは複数回リプレイされて毎回同じ結果を生成する必要があるため、確定的である必要があります。For example, orchestrator code must be deterministic, as it will be replayed multiple times and must produce the same result each time. 制約に関する完全なリストについては、チェックポイントの設定と再起動に関する記事の「Orchestrator code constraints (オーケストレーター コードの制約)」セクションをご覧ください。The complete list of constraints can be found in the Orchestrator code constraints section of the Checkpointing and restart article.

言語のサポートLanguage support

現時点では、Durable Functions でサポートされている言語は、C# (Functions v1 と v2)、F# と JavaScript (Functions v2 のみ) だけです。Currently C# (Functions v1 and v2), F# and JavaScript (Functions v2 only) are the only supported languages for Durable Functions. これには、オーケストレーター関数とアクティビティ関数が含まれます。This includes orchestrator functions and activity functions. 今後、Azure Functions でサポートされているすべての言語をサポートしていく予定です。In the future, we will add support for all languages that Azure Functions supports. 言語サポートの追加に関する最新の進捗状況については、Azure Functions の GitHub リポジトリの Issue 一覧をご覧ください。See the Azure Functions GitHub repository issues list to see the latest status of our additional language support work.

監視と診断Monitoring and diagnostics

Durable Functions 拡張機能は、Application Insights インストルメンテーション キーで関数アプリが構成されるときに、構造化された追跡データを Application Insights に自動で出力します。The Durable Functions extension automatically emits structured tracking data to Application Insights when the function app is configured with an Application Insights instrumentation key. この追跡データは、オーケストレーションの動作や進行状況を監視するために使用できます。This tracking data can be used to monitor the behavior and progress of your orchestrations.

Application Insights Analytics を使用すると Application Insights ポータル内で Durable Functions の追跡イベントがどのように表示されるか、その例を次に示します。Here is an example of what the Durable Functions tracking events look like in the Application Insights portal using Application Insights Analytics:

App Insights のクエリ結果

各ログ エントリの customDimensions フィールドには、有用な構造化データが数多く格納されています。There is a lot of useful structured data packed into the customDimensions field in each log entry. 完全に展開された、そのようなエントリの例を次に示します。Here is an example of one such entry fully expanded.

App Insights クエリの customDimensions フィールド

Durable Task Framework ディスパッチャーのリプレイ動作のおかげで、リプレイされたアクションの豊富なログ エントリを確認できます。Because of the replay behavior of the Durable Task Framework dispatcher, you can expect to see redundant log entries for replayed actions. これはコア エンジンのリプレイ動作を理解するのに役立ちます。This can be useful to understand the replay behavior of the core engine. 診断に関する記事では、リプレイ ログをフィルターで除外したサンプル クエリを示しているため、"リアルタイム" ログを確認できます。The Diagnostics article shows sample queries that filter out replay logs so you can see just the "real-time" logs.

ストレージとスケーラビリティStorage and scalability

Durable Functions 拡張機能は、Azure Storage の Queue、Table、BLOB を使用して実行履歴の状態を保持し、関数の実行をトリガーします。The Durable Functions extension uses Azure Storage queues, tables, and blobs to persist execution history state and trigger function execution. 関数アプリの既定のストレージ アカウントを使用、または別のストレージ アカウントを構成できます。The default storage account for the function app can be used, or you can configure a separate storage account. ストレージのスループット制限が原因で、別のアカウントを使用したいと思うこともあるでしょう。You might want a separate account due to storage throughput limits. 記述するオーケストレーター コードは、これらのストレージ アカウント内のエンティティとやりとりをする必要はありません (というより、すべきではありません)。The orchestrator code you write does not need to (and should not) interact with the entities in these storage accounts. エンティティは実装の詳細として、Durable Task Framework により直接管理されます。The entities are managed directly by the Durable Task Framework as an implementation detail.

オーケストレーター関数はアクティビティ関数をスケジュールし、内部キュー メッセージを介して応答を受け取ります。Orchestrator functions schedule activity functions and receive their responses via internal queue messages. Azure Functions の従量課金プランで関数アプリを実行するときは、これらのキューは Azure Functions Scale Controller により監視され、必要に応じてコンピューティング インスタンスが追加されます。When a function app runs in the Azure Functions Consumption plan, these queues are monitored by the Azure Functions Scale Controller and new compute instances are added as needed. オーケストレーター関数は、複数の VM にスケールアウトされるときに、呼び出すアクティビティ関数を複数の異なる VM で実行しつつ、1 つの VM 上で実行される場合があります。When scaled out to multiple VMs, an orchestrator function may run on one VM while activity functions it calls run on several different VMs. Durable Functions のスケール動作の詳細については、パフォーマンスとスケールに関する記事をご覧ください。You can find more details on the scale behavior of Durable Functions in Performance and scale.

Table Storage は、オーケストレーター アカウントの実行履歴を格納するために使用されます。Table storage is used to store the execution history for orchestrator accounts. 特定の VM 上でインスタンスが復元される場合は常に、そのローカルの状態を再構築できるようにするために、テーブルから実行履歴がフェッチされます。Whenever an instance rehydrates on a particular VM, it fetches its execution history from table storage so that it can rebuild its local state. Table Storage 内で履歴を使用できるようにすることの便利な点の 1 つは、Microsoft Azure Storage Explorer などのツールを使用してオーケストレーションの履歴を確認できることです。One of the convenient things about having the history available in Table storage is that you can take a look and see the history of your orchestrations using tools such as Microsoft Azure Storage Explorer.

Azure Storage Explorer のスクリーン ショット

警告

Table Storage 内で実行履歴を確認できるのは簡単で便利ですが、このテーブルに依存関係を設定することは避けてください。While it's easy and convenient to see execution history in table storage, avoid taking any dependency on this table. これについては、Durable Functions 拡張機能が今後改善されていくうちに変更される可能性があります。It may change as the Durable Functions extension evolves.

既知の問題とよくあるご質問Known issues and FAQ

すべての既知の問題は、GitHub の Issue 一覧で追跡されています。All known issues should be tracked in the GitHub issues list. 問題が発生してその問題が GitHub で見つからない場合は、新しい Issue を開き、その問題の詳細な説明を記載してお知らせください。If you run into a problem and can't find the issue in GitHub, open a new issue and include a detailed description of the problem.

次の手順Next steps