Modes d’exécution du flux de travail

Lors de l’exécution d’un flux de travail dans .NET, le mode d’exécution contrôle la façon dont les supersteps sont traités et la façon dont les événements sont remis au consommateur. La InProcessExecution classe expose deux modes d’exécution : OffThread et Lockstep.

Aperçu

OffThread (valeur par défaut) Lockstep
Exécution de superstep Thread d’arrière-plan Thread du consommateur
Livraison d’événements Immédiatement, à mesure que les événements sont déclenchés Traitée par lots après chaque superétape achevée.
Exécution de l’étape Indépendant du traitement des événements Mise en pause jusqu'à ce que les événements groupés soient consommés.
Concurrence Le consommateur lit les événements pendant que les superétapes s'exécutent Alternance de l'exécution du consommateur et du superstep
Idéal pour Streaming en temps réel, scénarios de production Test, débogage, classement déterministe

En dehors du thread

OffThread est le mode d’exécution par défaut . Les supersteps s’exécutent sur un thread d’arrière-plan et les événements sont diffusés immédiatement dès qu'ils sont déclenchés via une implémentation par 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);

Fonctionnement

  1. Une tâche en arrière-plan s’exécute en continu pendant que les messages sont en attente.
  2. À mesure que les exécuteurs produisent des sorties ou des événements, les objets résultants WorkflowEvent sont écrits dans un objet non lié Channel<WorkflowEvent>.
  3. Le consommateur lit les événements à partir du canal via WatchStreamAsync, les recevant en temps réel à mesure qu’ils sont produits.
  4. Lorsque tous les supersteps sont terminés et qu'aucun message ne reste à traiter, l'exécution s'arrête avec un statut Idle ou PendingRequests.

Étant donné que la boucle superstep et le consommateur s’exécutent simultanément, les événements apparaissent dès qu’ils sont déclenchés : il n’y a aucun délai de mise en mémoire tampon. Cela rend OffThread idéal pour les scénarios de diffusion en continu où la remise d’événements à faible latence est importante, telles que l’affichage des mises à jour de jeton par jeton dans une interface utilisateur.

Exécutions simultanées

OffThread prend également en charge une variante simultanée qui permet à plusieurs exécutions de partager simultanément la même instance de flux de travail :

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

Important

L’exécution simultanée nécessite que tous les exécuteurs du flux de travail soient déclarés crossRunShareable (sur le constructeur) ou fournis en tant que méthodes de fabrique.

Lockstep

En mode Lockstep, les supersteps s’exécutent dans le thread du consommateur plutôt que sur une tâche en arrière-plan. Les événements sont accumulés pendant chaque superstep et émis en tant que lot une fois le superstep terminé.

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

Fonctionnement

  1. Le consommateur appelle WatchStreamAsync, qui pilote la boucle d’exécution.
  2. Un superstep s’exécute jusqu’à la fin, et les événements sont accumulés dans une file d’attente.
  3. Une fois le superstep terminé, tous les événements mis en file d'attente sont rendus auprès du consommateur.
  4. Le superstep suivant commence uniquement une fois que le consommateur a reçu tous les événements de la superétape précédente.

Ce modèle alternatif signifie que le consommateur et le moteur de workflow ne s’exécutent jamais simultanément. La remise des événements est déterministe : tous les événements d’un superstep sont assurés d'arriver avant ceux du prochain superstep.

Quand utiliser Lockstep

Lockstep est utile lorsque :

  • Test : l’ordre des événements déterministe rend les assertions simples.
  • Débogage : le débogage pas à pas est plus facile lorsque l’exécution reste sur le thread du consommateur.
  • Traitement ordonné : scénarios dans lesquels vous devez traiter entièrement les événements d’un superstep avant le début du prochain superstep.

Choix d’un mode d’exécution

Pour la plupart des scénarios de production, le mode OffThread par défaut est recommandé. Il offre la meilleure réactivité et permet au flux de travail de poursuivre le traitement pendant que le consommateur gère les événements.

Utilisez Lockstep lorsque le comportement déterministe est plus important que les performances, comme dans les tests unitaires ou les sessions de débogage.

// 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);

Exécution sans diffusion en continu

Les deux modes d’exécution prennent en charge l’exécution non continue via RunAsync. En mode non streaming, le flux de travail s’exécute jusqu’à la fin et collecte tous les événements dans un Run objet plutôt que de les diffuser en continu de manière incrémentielle :

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

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

Étant donné que l’exécution hors streaming collecte tous les événements après la fin, l’avantage de remise d’événements en temps réel de OffThread ne s’applique pas. La principale différence entre les modes dans les scénarios de non-diffusion en continu est threading : OffThread exécute des supersteps sur un thread d’arrière-plan, libérant le thread appelant en attendant l’achèvement, tandis que Lockstep exécute des supersteps sur le thread de l’appelant, le bloquant jusqu’à ce que le flux de travail se termine.

L’exécution hors streaming utilise le mode OffThread par défaut. Pour utiliser Lockstep avec une exécution sans diffusion en continu :

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

Étapes suivantes

Les modes d’exécution ne s’appliquent pas aux flux de travail Python. Les flux de travail Python utilisent un modèle d’exécution unique qui gère le traitement et la distribution d’événements en superstep via un générateur asynchrone. Ce modèle est similaire au mode Lockstep .NET. Les étapes ne sont pas avancées, sauf si le consommateur extrait activement les événements du générateur.

Pour plus d’informations sur l’exécution de flux de travail Python, consultez Workflow Builder &Execution.

Lors de l’exécution d’un flux de travail dans Go, l’environnement d’exécution contrôle la façon dont les supersteps sont traités et la façon dont les événements sont remis au consommateur. Le workflow/inproc package expose trois environnements : Default/OffThread, Lockstepet .Concurrent

Aperçu

OffThread / Par défaut Lockstep Simultané
Exécution de superstep Goroutine d’arrière-plan Piloté par le consommateur d’événements Goroutine d’arrière-plan
Livraison d’événements Immédiatement, à mesure que les événements sont déclenchés Traitement par lots à mesure que le flux est consommé Immédiatement, à mesure que les événements sont déclenchés
Idéal pour Streaming en temps réel, scénarios de production Test, débogage, classement déterministe Instances de flux de travail partagées avec liaisons sécurisées simultanées

En dehors du thread

OffThread est le mode d’exécution par défaut. Ceux-ci sont équivalents :

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

Fonctionnement

  1. Une goroutine en arrière-plan exécute des supersteps pendant que les messages sont en attente.
  2. À mesure que les exécuteurs produisent des sorties ou des événements, les événements de flux de travail sont écrits dans le flux.
  3. Le consommateur lit les événements avec WatchStream, en les recevant au fur et à mesure qu’ils sont produits.
  4. Lorsque tous les supersteps sont terminés et qu’aucun message ne reste, l’exécution s’interrompt avec un état inactif ou de requête en attente.

Exécutions simultanées

Utilisez inproc.Concurrent quand toutes les liaisons d’exécuteur dans le flux de travail prennent en charge l’exécution partagée simultanée :

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

Lockstep

En mode Lockstep, l’exécution du flux de travail avance à mesure que le consommateur lit à partir du flux. Cela rend l’ordre des événements déterministe pour les tests et le débogage.

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
}

Fonctionnement

  1. Le consommateur appelle WatchStream, qui pilote la boucle d’exécution.
  2. Un superstep s’exécute jusqu’à son achèvement, et les événements s’accumulent.
  3. Les événements accumulés sont transmis au consommateur.
  4. Le superstep suivant ne commence qu’après que le consommateur a reçu les événements du superstep précédent.

Quand utiliser Lockstep

Utilisez Lockstep lorsque le comportement déterministe importe plus que la diffusion en continu à faible latence, comme les tests unitaires, le débogage ou les scénarios dans lesquels vous souhaitez traiter entièrement les événements d’un superstep avant le début du superstep suivant.

Choix d’un mode d’exécution

Pour la plupart des scénarios de production, utilisez inproc.Default ou inproc.OffThread. Utiliser inproc.Lockstep quand l’ordre des événements déterministe est plus important que la latence de diffusion en continu, comme dans les tests. Utilisez inproc.Concurrent uniquement lorsque chaque liaison du flux de travail prend en charge l’exécution partagée simultanée.

// 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)

Exécution sans diffusion en continu

Tous les environnements d’exécution prennent également en charge l’exécution sans streaming Run, qui s’exécute jusqu’au prochain arrêt et stocke les événements émis dans l’exécution renvoyée.

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)
    }
}

Étapes suivantes