Orquestrações eternas

Orquestrações eternas são funções de orquestrador que são executadas indefinidamente redefinindo periodicamente seu próprio histórico usando a continue-as-new API. Eles são úteis para agregadores, trabalhos periódicos em segundo plano e qualquer cenário de Durable Functions que exija um loop infinito sem crescimento de histórico não limitado.

Sem continue-as-new, um orquestrador que executa em loop contínuo acumularia o histórico de orquestração a cada tarefa agendada, o que acabaria causando problemas de desempenho e uso excessivo de memória. O padrão de orquestração eterna resolve isso redefinindo o histórico em cada iteração.

Observação

Exemplos de código de orquestração eterno estão disponíveis para C#, JavaScript, Python e Java. O PowerShell não dá suporte a continue-as-new.

Neste artigo:

Orquestrações eternas são orquestrações que operam indefinidamente, redefinindo periodicamente seu próprio histórico usando a continue-as-new API. Eles são úteis para agregadores, trabalhos periódicos em segundo plano e qualquer cenário que exija um loop infinito sem crescimento de histórico não associado.

Sem continue-as-new, uma orquestração que faz loops para sempre acumularia histórico com cada tarefa agendada, eventualmente causando problemas de desempenho e uso excessivo de memória. O padrão de orquestração eterna resolve isso redefinindo o histórico em cada iteração.

Importante

Atualmente, o SDK da Tarefa Durável do PowerShell não está disponível.

Neste artigo:

Como a continuação como nova funciona

Em vez de usar loops infinitos, as funções de orquestrador redefinem seu estado chamando o método continue-as-new da associação de gatilho de orquestração. Esse método usa um parâmetro serializável JSON que se torna a nova entrada para a próxima geração de função do orquestrador.

Quando você chama continue-as-new, a instância de orquestração é reiniciada com o novo valor de entrada. A mesma ID de instância é mantida, mas o histórico da função de orquestrador redefine.

Em vez de usar loops infinitos, as orquestrações redefinem seu estado chamando o continue-as-new método no contexto de orquestração. Esse método usa um parâmetro serializável JSON que se torna a nova entrada para a próxima geração de orquestração.

Quando você chama continue-as-new, a instância de orquestração é reiniciada com o novo valor de entrada. A mesma ID da instância é mantida, mas o histórico da orquestração é redefinido.

Considerações sobre a orquestração contínua

Tenha estas considerações em mente ao usar o continue-as-new método em uma orquestração:

  • Quando uma função de orquestrador é redefinida usando o continue-as-new método, o Durable Task Framework mantém a mesma ID de instância, mas cria e usa internamente uma nova ID de execução daqui para frente. Este ID de execução não é exposto externamente, mas é útil ao solucionar problemas na execução da orquestração.

  • Quando uma exceção sem tratamento ocorre durante a execução, a orquestração insere um estado com falha e a execução é encerrada. Uma chamada de um bloco continue-as-newfinallynão reinicia a orquestração depois de uma exceção não capturada.

  • Os resultados de tarefas incompletas são descartados quando uma orquestração chama continue-as-new. Por exemplo, se um temporizador for agendado e continue-as-new for chamado antes do temporizador ser acionado, o evento de temporizador será descartado.

  • Opcionalmente, você pode preservar eventos externos não processados entre continue-as-new reinicializações. Em C#, ContinueAsNew preserva eventos não processados por padrão. Em Java, continueAsNew também preserva eventos por padrão. Em Python, continue_as_new não preserva eventos, a menos que save_events=True. No JavaScript, continueAsNew requer um saveEvents parâmetro (true ou false) para controlar esse comportamento.

Tenha estas considerações em mente ao usar o continue-as-new método em uma orquestração:

  • Quando uma orquestração é redefinida usando o continue-as-new método, os SDKs de Tarefa Durável mantêm a mesma ID de instância, mas criam e usam internamente uma nova ID de execução daqui para frente. Este ID de execução não é exposto externamente, mas pode ser útil ao depurar a execução de orquestração.

  • Quando uma exceção sem tratamento ocorre durante a execução, a orquestração insere um estado com falha e a execução é encerrada. Uma chamada de um bloco finally não reinicia a orquestração após uma exceção não capturada.

  • Os resultados de tarefas incompletas são descartados quando uma orquestração chama continue-as-new. Por exemplo, se um temporizador for agendado e continue-as-new for chamado antes do temporizador ser acionado, o evento de temporizador será descartado.

  • Opcionalmente, você pode preservar eventos externos não processados entre continue-as-new reinicializações. Em .NET e Java, continue-as-new preserva eventos não processados por padrão. Em Python, continue_as_new não preserva eventos, a menos que save_events=True. No JavaScript, continueAsNew requer um saveEvents parâmetro (true ou false) para controlar esse comportamento. Em todos os casos, eventos não processados são entregues quando a próxima orquestração chamar waitForExternalEvent ou wait_for_external_event.

Exemplo de trabalho periódico

Um caso de uso comum para orquestrações eternas é o trabalho periódico em segundo plano, como tarefas de limpeza.

Por que não usar um gatilho de temporizador? Um gatilho de temporizador baseado em CRON é executado em horários fixos, independentemente de a execução anterior ter sido concluída. Uma orquestração eterna aguarda a conclusão do trabalho antes de agendar a próxima iteração, portanto, as execuções nunca se sobrepõem.

Approach Agendamento (intervalo de 1 hora, trabalho de 30 minutos) Risco de sobreposição
Gatilho de temporizador (CRON) 1:00, 2:00, 3:00 Sim – se o trabalho exceder o intervalo
Orquestração eterna 1:00, 2:30, 4:00 Não — a próxima execução aguarda a conclusão
[FunctionName("Periodic_Cleanup_Loop")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    await context.CallActivityAsync("DoCleanup", null);

    // sleep for one hour between cleanups
    DateTime nextCleanup = context.CurrentUtcDateTime.AddHours(1);
    await context.CreateTimer(nextCleanup, CancellationToken.None);

    context.ContinueAsNew(null);
}
public class PeriodicCleanupLoop : TaskOrchestrator<object?, object?>
{
    public override async Task<object?> RunAsync(TaskOrchestrationContext context, object? input)
    {
        await context.CallActivityAsync("DoCleanup");

        // sleep for one hour between cleanups
        await context.CreateTimer(TimeSpan.FromHours(1), CancellationToken.None);

        context.ContinueAsNew(null);
        return null;
    }
}

Iniciar uma orquestração eterna

Use o método de cliente durável start-new ou schedule-new para iniciar uma orquestração infinita, da mesma forma que qualquer outra função de orquestração. Para garantir que apenas uma instância seja executada por vez, use uma ID de instância fixa. Para obter mais informações, consulte Orquestrações Singleton.

[FunctionName("Trigger_Eternal_Orchestration")]
public static async Task<HttpResponseMessage> OrchestrationTrigger(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage request,
    [DurableClient] IDurableOrchestrationClient client)
{
    string instanceId = "StaticId";

    await client.StartNewAsync("Periodic_Cleanup_Loop", instanceId); 
    return client.CreateCheckStatusResponse(request, instanceId);
}

Use o método de cliente schedule-new para iniciar uma orquestração eterna, assim como qualquer outra orquestração. Para garantir que apenas uma instância seja executada por vez, use uma ID de instância fixa. Para obter mais informações, consulte Orquestrações Singleton.

string instanceId = "StaticId";
await client.ScheduleNewOrchestrationInstanceAsync(
    "PeriodicCleanupLoop",
    null,
    new StartOrchestrationOptions { InstanceId = instanceId });

Sair de uma orquestração eterna

Se no final uma função de orquestrador precisar ser concluída, não chame continue-as-new e deixe a função sair.

Se uma função de orquestrador estiver em um loop infinito e precisar ser interrompida, use a API de encerramento da associação de cliente de orquestração para interrompê-la.

await client.TerminateAsync(instanceId, "Cleanup no longer needed");

Para obter mais informações, consulte o gerenciamento de instâncias.

Se no final uma função de orquestrador precisar ser concluída, não chame continue-as-new e deixe a orquestração sair.

Se uma orquestração estiver em um loop infinito e precisar ser interrompida, use a API terminate no cliente de tarefas duráveis para pará-la.

await client.TerminateInstanceAsync(instanceId, "Cleanup no longer needed");

Próximas Etapas