Orquestrações eternas

Orquestrações eternas são funções orquestradoras que funcionam indefinidamente, reiniciando periodicamente o seu histórico usando a API continue-as-new. São úteis para agregadores, trabalhos periódicos em segundo plano e qualquer cenário Durable Functions que exija um ciclo infinito sem crescimento de histórico ilimitado.

Sem continue-as-new, um orquestrador que repete ciclos indefinidamente acumularia histórico de orquestração com cada tarefa agendada, eventualmente causando problemas de desempenho e uso excessivo de memória. O padrão eterno de orquestração resolve isto ao reiniciar a história em cada iteração.

Observação

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

Neste artigo:

Orquestrações eternas são orquestrações que correm indefinidamente, reiniciando periodicamente a sua própria história usando a continue-as-new API. São úteis para agregadores, trabalhos periódicos de fundo e qualquer cenário que exija um ciclo infinito sem crescimento ilimitado da história.

Sem continue-as-new, uma orquestração que se repete indefinidamente acumularia histórico com cada tarefa agendada, eventualmente causando problemas de desempenho e uso excessivo de memória. O padrão eterno de orquestração resolve isto ao reiniciar a história em cada iteração.

Importante

Atualmente, o PowerShell Durable Task SDK não está disponível.

Neste artigo:

Como continua como novo funciona

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

Quando tu chamas continue-as-new, a instância de orquestração reinicia-se com o novo valor de entrada. O mesmo ID de instância é mantido, mas o histórico da função do orquestrador é reiniciado.

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

Quando tu chamas continue-as-new, a instância de orquestração reinicia-se com o novo valor de entrada. O mesmo ID de instância é mantido, mas o histórico da orquestração é redefinido.

Considerações sobre orquestração eterna

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

  • Quando uma função de orquestrador é reiniciada usando o continue-as-new método, o Durable Task Framework mantém o mesmo ID de instância, mas cria internamente e utiliza um novo ID de execução daqui para a frente. Este ID de execução não é exposto externamente, mas é útil para depurar a execução de orquestração.

  • Quando uma exceção não tratada ocorre durante a execução, a orquestração entra em um estado de falha e a execução é encerrada. Uma chamada a continue-as-new a partir de um bloco finallynão reinicia a orquestração após uma exceção não capturada.

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

  • Pode, opcionalmente, preservar eventos externos não processados em todos os reinícios continue-as-new. Em C#, ContinueAsNew preserva os eventos não processados por defeito. 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. Em JavaScript, continueAsNew requer um saveEvents parâmetro (true ou false) para controlar este comportamento.

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

  • Quando uma orquestração é reiniciada usando o continue-as-new método, os SDKs de Tarefas Duráveis mantêm o mesmo ID de instância, mas criam internamente e usam um novo ID de execução daqui para a frente. Esse ID de execução não é exposto externamente, mas pode ser útil ao depurar a execução de orquestração.

  • Quando uma exceção não tratada ocorre durante a execução, a orquestração entra em um estado de falha e a execução é encerrada. Uma chamada a continue-as-new partir de um finally bloco não reinicia a orquestração após uma exceção não detetada.

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

  • Pode, opcionalmente, preservar eventos externos não processados em todos os reinícios continue-as-new. Em .NET e Java, continue-as-new preserva eventos não processados por defeito. Em Python, continue_as_new não preserva eventos a menos que save_events=True. Em JavaScript, continueAsNew requer um saveEvents parâmetro (true ou false) para controlar este comportamento. Em todos os casos, eventos não processados são entregues quando a orquestração chama waitForExternalEvent novamente ou wait_for_external_event.

Exemplo de trabalho periódico

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

Porque não usar um temporizador? Um disparador de temporizador baseado em CRON executa-se em horários fixos, independentemente de a execução anterior ter terminado ou não. Uma orquestração contínua aguarda que a tarefa seja concluída antes de agendar a próxima iteração, garantindo assim que os processos nunca se sobreponham.

Approach Horário (intervalo de 1 hora, trabalho de 30 minutos) Risco de sobreposição
Gatilho 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 corrida espera para ser concluída
[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;
    }
}

Comece uma orquestração eterna

Use o método start-new ou schedule-new do cliente durável para iniciar uma orquestração perpétua, como qualquer função de orquestração. Para garantir que apenas uma instância corre de cada vez, use um ID de instância fixo. Para 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 schedule-new client para iniciar uma orquestração contínua, tal como se faz com qualquer outra orquestração. Para garantir que apenas uma instância corre de cada vez, use um ID de instância fixo. Para mais informações, consulte Orquestrações Singleton.

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

Saída de uma orquestração eterna

Se uma função orquestradora precisar eventualmente de ser concluída, não chame continue-as-new e deixe a função terminar.

Se uma função orchestrator estiver em um loop infinito e precisar ser interrompida, use a API terminate da ligação do cliente de orquestração para pará-la.

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

Para mais informações, consulte Gestão de Instâncias.

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

Se uma orquestração estiver num ciclo infinito e precisar de ser interrompida, use a API termine no cliente de tarefa durável para a parar.

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

Passos seguintes