O que são as Durable Functions?What are Durable Functions?

As Durable Functions são uma extensão do Azure Functions que permite escrever funções com estado em um ambiente de computação sem servidor.Durable Functions is an extension of Azure Functions that lets you write stateful functions in a serverless compute environment. A extensão permite definir fluxos de trabalho com estado pela escrita de funções de orquestrador e entidades com estado pela escrita de funções de entidade usando o modelo de programação do Azure Functions.The extension lets you define stateful workflows by writing orchestrator functions and stateful entities by writing entity functions using the Azure Functions programming model. Nos bastidores, a extensão gerencia o estado, os pontos de verificação e as reinicializações para você, permitindo que você se concentre na lógica de negócios.Behind the scenes, the extension manages state, checkpoints, and restarts for you, allowing you to focus on your business logic.

Linguagens compatíveisSupported languages

Atualmente, as Durable Functions dão suporte às seguintes linguagens:Durable Functions currently supports the following languages:

  • C# : bibliotecas de classes pré-compiladas e script C#.C#: both precompiled class libraries and C# script.
  • F# : bibliotecas de classes pré-compiladas e script F#.F#: precompiled class libraries and F# script. Só há suporte para o script F# na versão 1.x do Azure Functions Runtime.F# script is only supported for version 1.x of the Azure Functions runtime.
  • JavaScript: compatível apenas com a versão 2.x do Azure Functions Runtime.JavaScript: supported only for version 2.x of the Azure Functions runtime. Exige a versão 1.7.0 da extensão das Durable Functions ou uma versão posterior.Requires version 1.7.0 of the Durable Functions extension, or a later version.

As Durable Functions têm o objetivo de dar suporte a todas as linguagens do Azure Functions.Durable Functions has a goal of supporting all Azure Functions languages. Confira a lista de problemas das Durable Functions para obter o último status do trabalho para dar suporte a linguagens adicionais.See the Durable Functions issues list for the latest status of work to support additional languages.

Assim como o Azure Functions, há modelos para ajudá-lo a desenvolver as Durable Functions usando o Visual Studio 2019, o Visual Studio Code e o portal do Azure.Like Azure Functions, there are templates to help you develop Durable Functions using Visual Studio 2019, Visual Studio Code, and the Azure portal.

Padrões de aplicativoApplication patterns

O principal caso de uso das Durable Functions é simplificar requisitos complexos de coordenação com estado em aplicativos sem servidor.The primary use case for Durable Functions is simplifying complex, stateful coordination requirements in serverless applications. As seguintes seções descrevem padrões de aplicativo típicos que podem se beneficiar com as Durable Functions:The following sections describe typical application patterns that can benefit from Durable Functions:

Padrão 1: Encadeamento de funçõesPattern #1: Function chaining

No padrão de encadeamento de funções, uma sequência de funções é executada em uma ordem específica.In the function chaining pattern, a sequence of functions executes in a specific order. Nesse padrão, a saída de uma função é aplicada à entrada de outra função.In this pattern, the output of one function is applied to the input of another function.

Um diagrama do padrão de encadeamento de funções

Use as Durable Functions para implementar o padrão de encadeamento de funções de forma concisa, conforme mostrado no seguinte exemplo:You can use Durable Functions to implement the function chaining pattern concisely as shown in the following example:

C#C#

[FunctionName("Chaining")]
public static async Task<object> Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    try
    {
        var x = await context.CallActivityAsync<object>("F1", null);
        var y = await context.CallActivityAsync<object>("F2", x);
        var z = await context.CallActivityAsync<object>("F3", y);
        return  await context.CallActivityAsync<object>("F4", z);
    }
    catch (Exception)
    {
        // Error handling or compensation goes here.
    }
}

Javascript (somente funções 2.0)JavaScript (Functions 2.0 only)

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

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

Nesse exemplo, os valores F1, F2, F3 e F4 são os nomes de outras funções no aplicativo de funções.In this example, the values F1, F2, F3, and F4 are the names of other functions in the function app. Implemente o fluxo de controle usando construtos de codificação imperativa normal.You can implement control flow by using normal imperative coding constructs. O código é executado de cima para baixo.Code executes from the top down. Ele pode envolver a semântica do fluxo de controle da linguagem existente, como condicionais e loops.The code can involve existing language control flow semantics, like conditionals and loops. Você pode incluir a lógica de tratamento de erro em blocos try/catch/finally.You can include error handling logic in try/catch/finally blocks.

Use o parâmetro context [IDurableOrchestrationContext] (.NET) e o objeto context.df (JavaScript) para invocar outras funções por nome, passar parâmetros e retornar a saída da função.You can use the context parameter [IDurableOrchestrationContext] (.NET) and the context.df object (JavaScript) to invoke other functions by name, pass parameters, and return function output. Sempre que o código chama await (C#) ou yield (JavaScript), a estrutura das Durable Functions faz a verificação pontual do progresso da instância da função atual.Each time the code calls await (C#) or yield (JavaScript), the Durable Functions framework checkpoints the progress of the current function instance. Se o processo ou a VM for reciclada no meio da execução, a instância da função retomará na chamada await ou yield anterior.If the process or VM recycles midway through the execution, the function instance resumes from the preceding await or yield call. Para obter mais informações, confira a próxima seção, Padrão nº2: Fan-out/fan-in.For more information, see the next section, Pattern #2: Fan out/fan in.

Observação

O objeto context no JavaScript representa o contexto de função inteiro, não apenas o parâmetro [IDurableOrchestrationContext].The context object in JavaScript represents the entire function context, not only the [IDurableOrchestrationContext] parameter.

Padrão 2: Fan-out/fan-inPattern #2: Fan out/fan in

No padrão fan-out/fan-in, execute várias funções em paralelo e, em seguida, aguarde a conclusão de todas as funções.In the fan out/fan in pattern, you execute multiple functions in parallel and then wait for all functions to finish. Frequentemente, algum trabalho de agregação é feito nos resultados retornados pelas funções.Often, some aggregation work is done on the results that are returned from the functions.

Um diagrama do padrão fan-out/fan-in

Com funções normais, realize fan-out fazendo com que a função envie várias mensagens para uma fila.With normal functions, you can fan out by having the function send multiple messages to a queue. No entanto, o processo de realizar fan-in é muito mais complexo.Fanning back in is much more challenging. Para o fan-in, em uma função normal, você escreve o código a ser controlado quando as funções disparadas por fila terminam e, em seguida, armazena saídas da função.To fan in, in a normal function, you write code to track when the queue-triggered functions end, and then store function outputs.

A extensão Durable Functions cuida desse padrão com um código relativamente simples:The Durable Functions extension handles this pattern with relatively simple code:

C#C#

[FunctionName("FanOutFanIn")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var parallelTasks = new List<Task<int>>();

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

    await Task.WhenAll(parallelTasks);

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

JavaScript (somente funções 2.0)JavaScript (Functions 2.0 only)

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

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

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

    yield context.df.Task.all(parallelTasks);

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

O trabalho de fan-out é distribuído para várias instâncias da função F2.The fan-out work is distributed to multiple instances of the F2 function. O trabalho é acompanhado usando uma lista dinâmica de tarefas.The work is tracked by using a dynamic list of tasks. A API Task.WhenAll .NET ou context.df.Task.all JavaScript é chamada para aguardar até que todas as funções chamadas sejam concluídas.The .NET Task.WhenAll API or JavaScript context.df.Task.all API is called, to wait for all the called functions to finish. Em seguida, as saídas da função F2 são agregadas da lista de tarefas dinâmicas e passadas para a função F3.Then, the F2 function outputs are aggregated from the dynamic task list and passed to the F3 function.

O ponto de verificação automático que ocorre na chamada await ou yield em Task.WhenAll ou context.df.Task.all garante que uma possível falha ou reinicialização no meio do processo não exija a reinicialização de uma tarefa já concluída.The automatic checkpointing that happens at the await or yield call on Task.WhenAll or context.df.Task.all ensures that a potential midway crash or reboot doesn't require restarting an already completed task.

Observação

Em raras circunstâncias, é possível que uma falha ocorra na janela depois que uma função de atividade for concluída, mas antes de sua conclusão ser salva no histórico de orquestração.In rare circumstances, it's possible that a crash could happen in the window after an activity function completes but before its completion is saved into the orchestration history. Se isso acontecer, a função de atividade será executada novamente desde o início depois que o processo for recuperado.If this happens, the activity function would re-run from the beginning after the process recovers.

Padrão 3: APIs HTTP assíncronasPattern #3: Async HTTP APIs

O padrão de API HTTP assíncrona trata do problema de coordenar o estado de operações de execução longa com clientes externos.The async HTTP API pattern addresses the problem of coordinating the state of long-running operations with external clients. Uma maneira comum de implementar esse padrão é fazer com que um ponto de extremidade HTTP dispare a ação de execução longa.A common way to implement this pattern is by having an HTTP endpoint trigger the long-running action. Em seguida, redirecione o cliente para um ponto de extremidade de status que é sondado pelo cliente para saber quando a operação é concluída.Then, redirect the client to a status endpoint that the client polls to learn when the operation is finished.

Um diagrama do padrão de API HTTP

As Durable Functions fornecem suporte interno para esse padrão, simplificando ou, até mesmo, removendo o código que você precisa escrever para interagir com execuções de função de execução longa.Durable Functions provides built-in support for this pattern, simplifying or even removing the code you need to write to interact with long-running function executions. Por exemplo, as amostras de início rápido das Durable Functions (C# e JavaScript) mostram um comando REST simples que você pode usar para iniciar novas instâncias de função de orquestrador.For example, the Durable Functions quickstart samples (C# and JavaScript) show a simple REST command that you can use to start new orchestrator function instances. Depois que uma instância é iniciada, a extensão expõe as APIs HTTP de webhook que consultam o status da função de orquestrador.After an instance starts, the extension exposes webhook HTTP APIs that query the orchestrator function status.

O exemplo a seguir mostra os comandos REST que iniciam um orquestrador e consultam seu status.The following example shows REST commands that start an orchestrator and query its status. Para maior clareza, alguns detalhes do protocolo foram omitidos do exemplo.For clarity, some protocol 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/runtime/webhooks/durabletask/b79baf67f717453ca9e86c5da21e03ec

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

> curl https://myfunc.azurewebsites.net/runtime/webhooks/durabletask/b79baf67f717453ca9e86c5da21e03ec -i
HTTP/1.1 202 Accepted
Content-Type: application/json
Location: https://myfunc.azurewebsites.net/runtime/webhooks/durabletask/b79baf67f717453ca9e86c5da21e03ec

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

> curl https://myfunc.azurewebsites.net/runtime/webhooks/durabletask/b79baf67f717453ca9e86c5da21e03ec -i
HTTP/1.1 200 OK
Content-Length: 175
Content-Type: application/json

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

Como o runtime das Durable Functions gerencia o estado para você, você não precisa implementar seu próprio mecanismo de acompanhamento de status.Because the Durable Functions runtime manages state for you, you don't need to implement your own status-tracking mechanism.

A extensão Durable Functions expõe as APIs HTTP internas que gerenciam orquestrações de execução longa.The Durable Functions extension exposes built-in HTTP APIs that manage long-running orchestrations. Como alternativa, você pode implementar esse padrão por conta própria usando seus próprios gatilhos de função (como HTTP, uma fila ou os Hubs de Eventos do Azure) e a associação de cliente de orquestração.You can alternatively implement this pattern yourself by using your own function triggers (such as HTTP, a queue, or Azure Event Hubs) and the orchestration client binding. Por exemplo, você pode usar uma mensagem da fila para disparar o encerramento.For example, you might use a queue message to trigger termination. Ou você pode usar um gatilho HTTP protegido por uma política de autenticação do Azure Active Directory, em vez de APIs HTTP internas que usam uma chave gerada para autenticação.Or, you might use an HTTP trigger that's protected by an Azure Active Directory authentication policy instead of the built-in HTTP APIs that use a generated key for authentication.

Para obter mais informações, confira o artigo Recursos HTTP, que explica como você pode expor processos assíncronos de execução longa via HTTP usando a extensão das Durable Functions.For more information, see the HTTP features article, which explains how you can expose asynchronous, long-running processes over HTTP using the Durable Functions extension.

Padrão 4: MonitoramentoPattern #4: Monitor

O padrão de monitor refere-se a um processo recorrente e flexível em um fluxo de trabalho.The monitor pattern refers to a flexible, recurring process in a workflow. Um exemplo é fazer uma sondagem até que condições específicas sejam atendidas.An example is polling until specific conditions are met. Você pode usar um gatilho de temporizador normal para lidar com um cenário básico, como um trabalho de limpeza periódico, mas seu intervalo é estático e o gerenciamento do tempo de vida da instância torna-se complexo.You can use a regular timer trigger to address a basic scenario, such as a periodic cleanup job, but its interval is static and managing instance lifetimes becomes complex. Use as Durable Functions para criar intervalos de recorrência flexíveis, gerenciar os tempos de vida de tarefas e criar vários processos de monitor com base em uma única orquestração.You can use Durable Functions to create flexible recurrence intervals, manage task lifetimes, and create multiple monitor processes from a single orchestration.

Um exemplo do padrão de monitor é reverter o cenário de API HTTP assíncrona anterior.An example of the monitor pattern is to reverse the earlier async HTTP API scenario. Em vez de expor um ponto de extremidade para um cliente externo monitorar uma operação de execução longa, o monitor de execução longa consome um ponto de extremidade externo e, em seguida, aguarda uma alteração de estado.Instead of exposing an endpoint for an external client to monitor a long-running operation, the long-running monitor consumes an external endpoint, and then waits for a state change.

Um diagrama do padrão de monitor

Em poucas linhas de código, você pode usar as Durable Functions para criar vários monitores que observam pontos de extremidade arbitrários.In a few lines of code, you can use Durable Functions to create multiple monitors that observe arbitrary endpoints. Os monitores podem encerrar a execução quando uma condição é atendida ou o IDurableOrchestrationClient pode encerrar os monitores.The monitors can end execution when a condition is met, or the IDurableOrchestrationClient can terminate the monitors. Você pode alterar o intervalo de wait de um monitor de acordo com uma condição específica (por exemplo, retirada exponencial).You can change a monitor's wait interval based on a specific condition (for example, exponential backoff.)

O seguinte código implementa um monitor básico:The following code implements a basic monitor:

C#C#

[FunctionName("MonitorJobStatus")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    int jobId = context.GetInput<int>();
    int pollingInterval = GetPollingInterval();
    DateTime expiryTime = GetExpiryTime();

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

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

    // Perform more work here, or let the orchestration end.
}

JavaScript (somente funções 2.0)JavaScript (Functions 2.0 only)

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

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

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

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

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

Quando uma solicitação é recebida, uma nova instância de orquestração é criada para essa ID do trabalho.When a request is received, a new orchestration instance is created for that job ID. A instância sonda um status até que uma condição seja atendida e o loop seja encerrado.The instance polls a status until a condition is met and the loop is exited. Um temporizador durável controla o intervalo de sondagem.A durable timer controls the polling interval. Em seguida, mais trabalho pode ser realizado ou a orquestração pode ser encerrada.Then, more work can be performed, or the orchestration can end. Quando o context.CurrentUtcDateTime (.NET) ou o context.df.currentUtcDateTime (JavaScript) excede o valor expiryTime, o monitor é encerrado.When the context.CurrentUtcDateTime (.NET) or context.df.currentUtcDateTime (JavaScript) exceeds the expiryTime value, the monitor ends.

Padrão 5: Interação humanaPattern #5: Human interaction

Muitos processos automatizados envolvem algum tipo de interação humana.Many automated processes involve some kind of human interaction. Envolver humanos em um processo automatizado é complicado, porque as pessoas não estão tão altamente disponíveis nem são tão dinâmicas quanto os serviços de nuvem.Involving humans in an automated process is tricky because people aren't as highly available and as responsive as cloud services. Um processo automatizado pode permitir essa interação usando tempos limite e a lógica de compensação.An automated process might allow for this interaction by using timeouts and compensation logic.

Um processo de aprovação é um exemplo de um processo empresarial que envolve a interação humana.An approval process is an example of a business process that involves human interaction. A aprovação de um gerente pode ser necessária para um relatório de despesas que exceda determinado valor em dólares.Approval from a manager might be required for an expense report that exceeds a certain dollar amount. Se o gerente não aprovar o relatório de despesas em até 72 horas (talvez ele esteja de férias), um processo de escalonamento será iniciado para obter a aprovação de outra pessoa (talvez o gerente do gerente).If the manager doesn't approve the expense report within 72 hours (maybe the manager went on vacation), an escalation process kicks in to get the approval from someone else (perhaps the manager's manager).

Um diagrama do padrão de interação humana

Você pode implementar o padrão nesse exemplo usando uma função de orquestrador.You can implement the pattern in this example by using an orchestrator function. O orquestrador usa um temporizador durável para solicitar aprovação.The orchestrator uses a durable timer to request approval. O orquestrador fará o escalonamento se o tempo limite se esgotar.The orchestrator escalates if timeout occurs. O orquestrador aguarda um evento externo, como uma notificação gerada por uma interação humana.The orchestrator waits for an external event, such as a notification that's generated by a human interaction.

Estes exemplos criam um processo de aprovação para demonstrar o padrão de interação humana:These examples create an approval process to demonstrate the human interaction pattern:

C#C#

[FunctionName("ApprovalWorkflow")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    await context.CallActivityAsync("RequestApproval", null);
    using (var timeoutCts = new CancellationTokenSource())
    {
        DateTime dueTime = context.CurrentUtcDateTime.AddHours(72);
        Task durableTimeout = context.CreateTimer(dueTime, timeoutCts.Token);

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

JavaScript (somente funções 2.0)JavaScript (Functions 2.0 only)

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

module.exports = df.orchestrator(function*(context) {
    yield context.df.callActivity("RequestApproval");

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

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

Para criar o temporizador durável, chame context.CreateTimer (.NET) ou context.df.createTimer (JavaScript).To create the durable timer, call context.CreateTimer (.NET) or context.df.createTimer (JavaScript). A notificação é recebida pelo context.WaitForExternalEvent (.NET) ou context.df.waitForExternalEvent (JavaScript).The notification is received by context.WaitForExternalEvent (.NET) or context.df.waitForExternalEvent (JavaScript). Em seguida, Task.WhenAny (.NET) ou context.df.Task.any (JavaScript) é chamado para decidir se o próximo passo é escalonar (o tempo limite ocorre primeiro) ou processar a aprovação (a aprovação é recebida antes do tempo limite).Then, Task.WhenAny (.NET) or context.df.Task.any (JavaScript) is called to decide whether to escalate (timeout happens first) or process the approval (the approval is received before timeout).

Um cliente externo pode entregar a notificação de eventos para uma função de orquestrador em espera usando as APIs HTTP internas ou o método RaiseEventAsync (.NET) ou raiseEvent (JavaScript) em outra função:An external client can deliver the event notification to a waiting orchestrator function by using either the built-in HTTP APIs or by using the RaiseEventAsync (.NET) or raiseEvent (JavaScript) method from another function:

[FunctionName("RaiseEventToOrchestration")]
public static async Task Run(
    [HttpTrigger] string instanceId,
    [DurableClient] IDurableOrchestrationClient client)
{
    bool isApproved = true;
    await client.RaiseEventAsync(instanceId, "ApprovalEvent", isApproved);
}
const df = require("durable-functions");

module.exports = async function (context) {
    const client = df.getClient(context);
    const isApproved = true;
    await client.raiseEvent(instanceId, "ApprovalEvent", isApproved);
};
curl -d "true" http://localhost:7071/runtime/webhooks/durabletask/instances/{instanceId}/raiseEvent/ApprovalEvent -H "Content-Type: application/json"

Padrão nº 6: AgregadorPattern #6: Aggregator

O sexto padrão trata da agregação de dados de evento durante um período em uma única entidade endereçável.The sixth pattern is about aggregating event data over a period of time into a single, addressable entity. Nesse padrão, os dados que estão sendo agregados podem vir de várias fontes, podem ser entregues em lotes ou podem estar distribuídos por longos períodos.In this pattern, the data being aggregated may come from multiple sources, may be delivered in batches, or may be scattered over long-periods of time. O agregador pode precisar executar uma ação nos dados de evento quando eles são recebidos e os clientes externos talvez precisem consultar os dados agregados.The aggregator might need to take action on event data as it arrives, and external clients may need to query the aggregated data.

Diagrama do agregador

A complexidade de tentar implementar esse padrão com as funções normais sem estado é que o controle de simultaneidade se torna um grande desafio.The tricky thing about trying to implement this pattern with normal, stateless functions is that concurrency control becomes a huge challenge. Além de se preocupar com vários threads modificando os mesmos dados ao mesmo tempo, você precisa se preocupar em garantir que o agregador só seja executado em uma única VM por vez.Not only do you need to worry about multiple threads modifying the same data at the same time, you also need to worry about ensuring that the aggregator only runs on a single VM at a time.

Você pode usar Entidades duráveis para implementar facilmente esse padrão como uma única função.You can use Durable entities to easily implement this pattern as a single function.

[FunctionName("Counter")]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
    int currentValue = ctx.GetState<int>();
    switch (ctx.OperationName.ToLowerInvariant())
    {
        case "add":
            int amount = ctx.GetInput<int>();
            ctx.SetState(currentValue + amount);
            break;
        case "reset":
            ctx.SetState(0);
            break;
        case "get":
            ctx.Return(currentValue);
            break;
    }
}
const df = require("durable-functions");

module.exports = df.entity(function(context) {
    const currentValue = context.df.getState(() => 0);
    switch (context.df.operationName) {
        case "add":
            const amount = context.df.getInput();
            context.df.setState(currentValue + amount);
            break;
        case "reset":
            context.df.setState(0);
            break;
        case "get":
            context.df.return(currentValue);
            break;
    }
});

As entidades duráveis também podem ser modeladas como classes no .NET.Durable entities can also be modeled as classes in .NET. Esse modelo pode ser útil se a lista de operações é fixa e se torna grande.This model can be useful if the list of operations is fixed and becomes large. O exemplo a seguir é uma implementação equivalente da entidade Counter usando métodos e classes .NET.The following example is an equivalent implementation of the Counter entity using .NET classes and methods.

public class Counter
{
    [JsonProperty("value")]
    public int CurrentValue { get; set; }

    public void Add(int amount) => this.CurrentValue += amount;

    public void Reset() => this.CurrentValue = 0;

    public int Get() => this.CurrentValue;

    [FunctionName(nameof(Counter))]
    public static Task Run([EntityTrigger] IDurableEntityContext ctx)
        => ctx.DispatchAsync<Counter>();
}

Os clientes podem enfileirar operações de uma função de entidade (também conhecido como "sinalização") usando a associação do cliente de entidade.Clients can enqueue operations for (also known as "signaling") an entity function using the entity client binding.

[FunctionName("EventHubTriggerCSharp")]
public static async Task Run(
    [EventHubTrigger("device-sensor-events")] EventData eventData,
    [DurableClient] IDurableOrchestrationClient entityClient)
{
    var metricType = (string)eventData.Properties["metric"];
    var delta = BitConverter.ToInt32(eventData.Body, eventData.Body.Offset);

    // The "Counter/{metricType}" entity is created on-demand.
    var entityId = new EntityId("Counter", metricType);
    await entityClient.SignalEntityAsync(entityId, "add", delta);
}

Observação

Os proxies gerados dinamicamente também estão disponíveis no .NET para sinalizar entidades para torná-las fortemente tipadas.Dynamically generated proxies are also available in .NET for signaling entities in a type-safe way. Além da sinalização, os clientes também podem consultar o estado de uma função de entidade usando métodos fortemente tipados na associação do cliente de orquestração.And in addition to signaling, clients can also query for the state of an entity function using type-safe methods on the orchestration client binding.

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

module.exports = async function (context) {
    const client = df.getClient(context);
    const entityId = new df.EntityId("Counter", "myCounter");
    await context.df.signalEntity(entityId, "add", 1);
};

As funções de entidade estão disponíveis nas Durable Functions 2.0 e superior.Entity functions are available in Durable Functions 2.0 and above.

A tecnologiaThe technology

Nos bastidores, a extensão Durable Functions baseia-se na Durable Task Framework, uma biblioteca open-source no GitHub usada para a criação de fluxos de trabalho em código.Behind the scenes, the Durable Functions extension is built on top of the Durable Task Framework, an open-source library on GitHub that's used to build workflows in code. Assim como o Azure Functions é a evolução sem servidor do Azure WebJobs, as Durable Functions são a evolução sem servidor da Durable Task Framework.Like Azure Functions is the serverless evolution of Azure WebJobs, Durable Functions is the serverless evolution of the Durable Task Framework. A Microsoft e outras organizações usam a Durable Task Framework extensivamente para automatizar processos críticos.Microsoft and other organizations use the Durable Task Framework extensively to automate mission-critical processes. Ele é uma opção natural para o ambiente sem servidor do Azure Functions.It's a natural fit for the serverless Azure Functions environment.

Restrições de códigoCode constraints

Para fornecer garantias de execução confiáveis e de execução longa, as funções de orquestrador têm um conjunto de regras de codificação que precisam ser seguidas.In order to provide reliable and long-running execution guarantees, orchestrator functions have a set of coding rules that must be followed. Para obter mais informações, confira o artigo Restrições de código na função de orquestrador.For more information, see the Orchestrator function code constraints article.

CobrançaBilling

As Durable Functions são cobradas da mesma forma que o Azure Functions.Durable Functions are billed the same as Azure Functions. Para saber mais, confira Preços do Azure Functions.For more information, see Azure Functions pricing. Ao executar funções de orquestrador no plano de Consumo do Azure Functions, há alguns comportamentos de cobrança para sua informação.When executing orchestrator functions in the Azure Functions Consumption plan, there are some billing behaviors to be aware of. Para obter mais informações sobre esses comportamentos, confira o artigo Cobrança das Durable Functions.For more information on these behaviors, see the Durable Functions billing article.

Comece a usar agoraJump right in

Comece a usar as Durable Functions em menos de 10 minutos concluindo um destes tutoriais de início rápido específicos a uma linguagem:You can get started with Durable Functions in under 10 minutes by completing one of these language-specific quickstart tutorials:

Nos dois inícios rápidos, você criará e testará uma durable function "Olá, Mundo" localmente.In both quickstarts, you locally create and test a "hello world" durable function. Em seguida, você publicará o código de função no Azure.You then publish the function code to Azure. A função que você criará orquestra e encadeia chamadas para outras funções.The function you create orchestrates and chains together calls to other functions.

Saiba maisLearn more

O seguinte vídeo destaca os benefícios das Durable Functions:The following video highlights the benefits of Durable Functions:

Para obter uma discussão mais detalhada sobre as Durable Functions e a tecnologia subjacente, confira o seguinte vídeo (ele se concentra no .NET, mas os conceitos também se aplicam a outras linguagens compatíveis):For a more in-depth discussion of Durable Functions and the underlying technology, see the following video (it's focused on .NET, but the concepts also apply to other supported languages):

Como as Durable Functions são uma extensão avançada do Azure Functions, elas não são apropriadas para todos os aplicativos.Because Durable Functions is an advanced extension for Azure Functions, it isn't appropriate for all applications. Para obter uma comparação com outras tecnologias de orquestração do Azure, confira Comparar o Azure Functions e os Aplicativos Lógicos do Azure.For a comparison with other Azure orchestration technologies, see Compare Azure Functions and Azure Logic Apps.

Próximas etapasNext steps