Modos de Execução do Fluxo de Trabalho

Ao executar um fluxo de trabalho em .NET, o modo de execução controla como os supersteps são processados e como os eventos são entregues ao consumidor. A InProcessExecution classe expõe dois modos de execução: OffThread e Lockstep.

Descrição geral

OffThread (Padrão) Lockstep
Execução do Superstep Tópico de fundo Discussão do Consumidor
Realização de eventos Imediato, à medida que os acontecimentos são levantados Agrupado cada vez que um superpasso é concluído
Execução de passos Independente do processamento de eventos Pausa até que os eventos em lote sejam consumidos
Concorrência O consumidor lê eventos enquanto os superpassos são executados Execução alternada entre consumidor e superstep
Melhor para Streaming em tempo real, cenários de produção Testes, depuração, ordenação determinística

OffThread

OffThread é o modo de execução padrão . Os supersteps correm numa thread em segundo plano e os eventos são transmitidos em tempo real assim que são gerados através de uma implementação baseada em canal.

// OffThread is the default — these are equivalent:
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input);
await using StreamingRun run = await InProcessExecution.OffThread.RunStreamingAsync(workflow, input);

Como funciona

  1. Uma tarefa em segundo plano executa supersteps continuamente enquanto as mensagens estão pendentes.
  2. À medida que os executores produzem saídas ou eventos, os objetos resultantes WorkflowEvent são escritos num objeto ilimitado Channel<WorkflowEvent>.
  3. O consumidor lê os eventos do canal via WatchStreamAsync, recebendo-os em tempo real à medida que são produzidos.
  4. Quando todos os superpassos estão concluídos e não restam mensagens, a execução termina com um estado Idle ou PendingRequests.

Como o ciclo de superpassos e o consumidor operam simultaneamente, os eventos aparecem assim que são gerados — não há atraso de armazenamento temporário. Isto torna o OffThread ideal para cenários de streaming onde a entrega de eventos com baixa latência é importante, como a apresentação de atualizações token a token numa interface.

Corridas simultâneas

O OffThread também suporta uma variante concorrente que permite que múltiplas execuções partilhem simultaneamente a mesma instância de workflow:

await using StreamingRun run = await InProcessExecution.Concurrent.RunStreamingAsync(workflow, input);

Importante

A execução concorrente requer que todos os executores do fluxo de trabalho sejam declarados crossRunShareable (no construtor) ou fornecidos como métodos de fábrica.

Lockstep

No modo Lockstep, os supersteps executam-se no thread do consumidor em vez de numa tarefa em segundo plano. Os eventos são acumulados durante cada superpasso e emitidos em conjunto após a conclusão do superpasso.

await using StreamingRun run = await InProcessExecution.Lockstep.RunStreamingAsync(workflow, input);

Como funciona

  1. O consumidor chama WatchStreamAsync, que gere o ciclo de execução.
  2. Um superpasso é executado até à conclusão e os eventos são acumulados numa fila.
  3. Após o superstep terminar, todos os eventos em fila são entregues ao consumidor.
  4. A próxima superetapa só se inicia depois que o consumidor tenha recebido todos os eventos da anterior.

Este padrão alternado significa que o consumidor e o motor de fluxo de trabalho nunca funcionam em simultâneo. A entrega de eventos é determinística — todos os eventos de um superpasso têm garantia de chegar antes de qualquer evento do próximo superpasso.

Quando usar o Lockstep

O lockstep é útil quando:

  • Testes — ordenação determinística de eventos torna as asserções simples.
  • Depuração — a depuração passo a passo é mais fácil quando a execução permanece na thread do consumidor.
  • Processamento ordenado — cenários em que precisa de processar totalmente os eventos de um superpasso antes de começar o próximo superpasso.

Escolha de um Modo de Execução

Para a maioria dos cenários de produção, recomenda-se o modo OffThread predefinido. Proporciona a melhor capacidade de resposta e permite que o fluxo de trabalho continue a processar enquanto o consumidor gere os eventos.

Use o Lockstep quando o comportamento determinístico for mais importante do que o desempenho, como em testes unitários ou sessões de depuração.

// Production: OffThread (default)
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, input);

// Testing: Lockstep for deterministic behavior
await using StreamingRun run = await InProcessExecution.Lockstep.RunStreamingAsync(workflow, input);

Execução Não-Streaming

Ambos os modos de execução suportam execução não em fluxo contínuo via RunAsync. No modo não-streaming, o fluxo de trabalho corre até ao fim e recolhe todos os eventos num Run objeto em vez de os transmitir incrementalmente:

Run run = await InProcessExecution.RunAsync(workflow, input);

// Access all emitted events
foreach (WorkflowEvent evt in run.OutgoingEvents)
{
    // Process events
}

Uma vez que a execução não transmissiva recolhe todos os eventos após a conclusão, o benefício da entrega de eventos em tempo real do OffThread não se aplica. A principal diferença entre os modos em cenários não streaming é o threading: o OffThread executa os supersteps em um thread em segundo plano, liberando o thread chamador enquanto aguarda a conclusão, enquanto o Lockstep executa supersteps no thread do chamador, bloqueando-o até que o fluxo de trabalho termine.

A execução não-streaming utiliza o modo OffThread predefinido. Para usar o Lockstep com execução sem streaming:

Run run = await InProcessExecution.Lockstep.RunAsync(workflow, input);

Passos seguintes

Os modos de execução não são aplicáveis a fluxos de trabalho em Python. Os fluxos de trabalho em Python utilizam um único modelo de execução que gere o processamento superstep e a entrega de eventos através de um gerador assíncrono. Este modelo é semelhante ao modo .NET Lockstep — os passos não avançam a menos que o consumidor esteja ativamente a extrair eventos do gerador.

Para informações sobre a execução de fluxos de trabalho em Python, consulte Workflow Builder & Execution.

Ao executar um fluxo de trabalho no Go, o ambiente de execução controla como os supersteps são processados e como os eventos são entregues ao consumidor. O workflow/inproc pacote expõe três ambientes: Default/OffThread, Lockstep, e Concurrent.

Descrição geral

OffThread / Padrão Lockstep Concomitante
Execução do Superstep Goroutine em segundo plano Orientado pelo consumidor de eventos Goroutine de fundo
Realização de eventos Imediato, à medida que os acontecimentos são levantados Agrupado em lotes à medida que o fluxo é consumido Imediato, à medida que os acontecimentos são levantados
Melhor para Streaming em tempo real, cenários de produção Testes, depuração, ordenação determinística Instâncias de fluxo de trabalho partilhadas com associações concorrentes seguras

OffThread

OffThread é o modo de execução padrão. Estes são equivalentes:

stream, err := inproc.Default.RunStreaming(ctx, wf, input)
stream, err := inproc.OffThread.RunStreaming(ctx, wf, input)

Como funciona

  1. Uma goroutine em segundo plano executa superpassos enquanto houver mensagens pendentes.
  2. À medida que os executores geram saídas ou eventos, os eventos do fluxo de trabalho são escritos no fluxo.
  3. O consumidor lê eventos com WatchStream, recebendo-os à medida que são produzidos.
  4. Quando todas as superetapas estiverem concluídas e não restarem mensagens, a execução é interrompida com um estado inativo ou de pedido pendente.

Corridas simultâneas

Use inproc.Concurrent quando todas as associações de executores no fluxo de trabalho suportam execução partilhada concorrente:

stream, err := inproc.Concurrent.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer stream.Close(ctx)

Lockstep

No modo Lockstep, a execução do fluxo de trabalho avança à medida que o consumidor lê do fluxo de dados. Isto torna a ordenação de eventos determinística para testes e depuração.

stream, err := inproc.Lockstep.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer stream.Close(ctx)

for evt, err := range stream.WatchStream(ctx) {
    if err != nil {
        return err
    }
    // inspect event
}

Como funciona

  1. O consumidor chama WatchStream, que gere o ciclo de execução.
  2. Um superpasso é executado até à sua conclusão e os eventos são acumulados.
  3. Os eventos acumulados são fornecidos ao consumidor.
  4. O próximo superstep só começa depois de o consumidor receber os eventos do superstep anterior.

Quando usar o Lockstep

Use o Lockstep quando o comportamento determinístico for mais importante do que o streaming de baixa latência, como testes unitários, depuração ou cenários em que quer processar totalmente os eventos de um superstep antes do início do próximo superstep.

Escolha de um Modo de Execução

Para a maioria dos cenários de produção, use inproc.Default ou inproc.OffThread. Uso inproc.Lockstep quando a ordenação determinística de eventos é mais importante do que a latência de streaming, como em testes. Use inproc.Concurrent apenas quando cada binding no fluxo de trabalho suporta execução partilhada simultânea.

// Production: OffThread (default)
stream, err := inproc.Default.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer stream.Close(ctx)

// Testing: Lockstep for deterministic behavior
testStream, err := inproc.Lockstep.RunStreaming(ctx, wf, input)
if err != nil {
    return err
}
defer testStream.Close(ctx)

Execução Não-Streaming

Todos os ambientes de execução também suportam o modo não contínuo Run, que é executado até à interrupção seguinte e armazena os eventos emitidos na execução devolvida.

run, err := inproc.Default.Run(ctx, wf, input)
if err != nil {
    return err
}

for evt := range run.NewEvents() {
    if output, ok := evt.(workflow.OutputEvent); ok {
        fmt.Printf("Final result: %v\n", output.Output)
    }
}

Passos seguintes