Avec le streaming de réponse activé, si le client se déconnecte (actualisation du navigateur) tandis que l’Agent IA continue le streaming, l’exécution est abandonnée et affiche { “isArtificialRecoveredEventItem”: true } avec « Execution stopped at this node. » J’aimerais que l’exécution se termine côté serveur même si le client se déconnecte, tout en gardant le streaming activé.
Reproduction minimale (n8n vanilla, pas de nœuds personnalisés)
- Chat Trigger (ou Webhook avec Response Mode: Streaming).
- Nœud AI Agent avec enableStreaming: true, connecté à :
- n’importe quel Chat Model (par ex. OpenAI Chat Model),
- n’importe quel outil qui prend quelques secondes (par ex. un outil HTTP Request frappant un endpoint lent — n’importe quoi qui garde l’agent occupé assez longtemps pour actualiser).
- Ouvrez le chat intégré, envoyez un message qui fait appeler l’outil par l’agent.
- Actualisez la page immédiatement, pendant que c’est encore en train de streamer.
- Ouvrez l’exécution → elle est arrêtée, output de AI Agent = { “isArtificialRecoveredEventItem”: true }.
Environnement
- n8n : Cloud, version 2.27.4
- Nœud AI Agent v3.1, Webhook v2.1 (responseMode: streaming)
Attendu vs réel
- Attendu : la perte du stream par le client ne devrait pas abandonner la run ; l’agent (et tous les effets secondaires des outils) devraient se terminer côté serveur.
- Réel : la run est abandonnée dès que la connexion de streaming se coupe → élément récupéré/artificiel.
Ce que j’ai essayé
- Désactiver enableStreaming sur l’AI Agent l’évite — mais alors il n’y a pas de streaming (désactiver le streaming sur l’un ou l’autre nœud revient à request-response).
- Je sais que le pattern asynchrone immediate-response / two-webhook existe, mais il supprime le streaming en direct.
Question
Y a-t-il un moyen supporté de découpler la durée de vie de l’exécution de la connexion HTTP de streaming — c’est-à-dire garder le streaming activé mais laisser l’exécution se terminer (ne pas abandonner) quand le client se déconnecte au milieu du stream ? N’importe quel paramètre, ou pattern recommandé ?
Voulez-vous que je :
- Exporte 1 workflow minimal (Chat Trigger + AI Agent + 1 outil simulant une lenteur + LLM) en JSON pour que vous l’attachiez — repro immédiate, augmentez fortement les chances d’être aidé ?
- Ou gardez celle-ci et vous remplissez vous-même la version + attachez une capture d’écran ?
Avec le streaming de réponse activé, si le client se déconnecte (actualisation du navigateur) tandis que l’Agent IA continue le streaming, l’exécution est abandonnée et affiche { “isArtificialRecoveredEventItem”: true } avec « Execution stopped at this node. » J’aimerais que l’exécution se termine côté serveur même si le client se déconnecte, tout en gardant le streaming activé.
Reproduction minimale (n8n vanilla, pas de nœuds personnalisés)
- Chat Trigger (ou Webhook avec Response Mode: Streaming).
- Nœud AI Agent avec enableStreaming: true, connecté à :
- n’importe quel Chat Model (par ex. OpenAI Chat Model),
- n’importe quel outil qui prend quelques secondes (par ex. un outil HTTP Request frappant un endpoint lent — n’importe quoi qui garde l’agent occupé assez longtemps pour actualiser).
- Ouvrez le chat intégré, envoyez un message qui fait appeler l’outil par l’agent.
- Actualisez la page immédiatement, pendant que c’est encore en train de streamer.
- Ouvrez l’exécution → elle est arrêtée, output de AI Agent = { “isArtificialRecoveredEventItem”: true }.
Environnement
- n8n : Cloud, version
- Nœud AI Agent v3.1, Webhook v2.1 (responseMode: streaming)
Attendu vs réel
- Attendu : la perte du stream par le client ne devrait pas abandonner la run ; l’agent (et tous les effets secondaires des outils) devraient se terminer côté serveur.
- Réel : la run est abandonnée dès que la connexion de streaming se coupe → élément récupéré/artificiel.
Ce que j’ai essayé
- Désactiver enableStreaming sur l’AI Agent l’évite — mais alors il n’y a pas de streaming (désactiver le streaming sur l’un ou l’autre nœud revient à request-response).
- Je sais que le pattern asynchrone immediate-response / two-webhook existe, mais il supprime le streaming en direct.
@sawsew467 pas de bouton intégré pour l’un des trois, le streaming lie l’exécution à la connexion active, donc une déconnexion la détruit (cet élément récupéré est le marqueur générique « tué avant la fin » de n8n, pas un vrai OOM), et il n’y a rien de documenté pour le découpler ou le réattacher. La solution est de ne pas exécuter le travail critique dans l’exécution en streaming, transférer l’agent + l’écriture mémoire vers une exécution non-streaming distincte qui se termine côté serveur, et laisser le client relire l’historique au rechargement. Et extraire les outils avec effets secondaires comme l’envoi d’email du stream pour qu’ils ne puissent pas s’exécuter sur un tour qui ne persiste jamais.
Bonjour @sawsew467,
Ce marqueur isArtificialRecoveredEventItem indique que l’exécution a planté plutôt que d’avoir été annulée proprement. Quand le navigateur se déconnecte, la socket TCP se ferme, et l’appel res.write() suivant à l’intérieur du gestionnaire de chunks de streaming de n8n lève une erreur EPIPE. Cela remonte la chaîne de callbacks LangChain jusqu’au moteur de workflow, qui fait planter l’exécution en vol. Le service de récupération remplit ensuite ce placeholder artificiel pour n’importe quel nœud qui a démarré mais n’a jamais persisté sa sortie.
Donc la connexion SSE et l’exécution côté serveur sont architecturalement couplées dans l’implémentation actuelle du streaming de n8n. Il n’y a pas de drapeau de configuration pour les découpler.
Vos options réelles :
1. Désactiver le streaming sur le nœud AI Agent : ce que vous avez déjà essayé, mais c’est utile de le nommer clairement : l’exécution s’achève côté serveur sans risque de déconnexion, et la réponse complète est retournée quand le workflow se termine. Le compromis UX est réel mais l’exécution est fiable.
2. Répondre immédiatement, puis interroger : Utilisez un nœud Webhook défini sur « Respond Immediately ». Il retourne un executionId immédiatement, le workflow s’exécute complètement en arrière-plan sans réponse HTTP attachée (pas de connexion SSE à perdre), et le client interroge GET /api/v1/executions/{id} pour le résultat. Les outils lents s’achèveront toujours. Vous perdez l’UX de streaming mais gagnez une exécution déterministe. Sur Cloud, vous restez dans le délai d’exécution de 5 minutes tant que votre HTTP Request n’est pas absurdement lent.
3. Mode workers en file d’attente : auto-hébergé uniquement, non disponible sur Cloud. Même dans ce cas, il est incertain que les échecs d’écriture du streaming sur le processus principal découplent complètement l’état d’exécution des workers.
Pour votre configuration spécifique, l’option 2 est probablement le meilleur chemin si vous avez besoin que les outils s’achèvent toujours. L’UX du polling est moins élégant que SSE mais beaucoup plus prévisible que d’espérer que le client reste connecté.
Si le streaming avec tolérance aux déconnexions est critique, cela nécessiterait un changement dans la façon dont n8n gère les erreurs d’écriture SSE, spécifiquement en ne les propageant pas dans le moteur d’exécution.
Les deux réponses ci-dessus ont raison : le streaming d’agent intégré d’n8n lie le travail à la requête en direct, donc une déconnexion arrête l’exécution, et il n’y a pas de flag pour les découpler aujourd’hui. Mais vous pouvez quand même obtenir une UX de streaming et une exécution garantie côté serveur en même temps. L’astuce consiste à arrêter le streaming via la requête d’n8n et à déplacer le flux vers un canal auquel le client s’abonne indépendamment.
Une architecture qui fonctionne :
-
Traitez le tour comme une tâche de fond durable. Prenez l’option 2 de PurveshGandhi comme base : le webhook répond immédiatement avec un ID de tour, l’agent s’exécute jusqu’au bout côté serveur sans SSE attaché, et l’écriture en mémoire se fait de toute façon. Cela seul rend le travail qui doit survivre à l’épreuve des déconnexions.
-
Récupérez le streaming en écrivant les chunks dans un canal externe, pas dans la réponse HTTP. Au fur et à mesure que le tour produit une sortie, écrivez-la sur quelque chose auquel le navigateur peut s’abonner indépendamment : une ligne Supabase realtime, Redis pub/sub, Ably, ou même une colonne partial_response que le client interroge quelques fois par seconde. Le navigateur lit à partir de ce canal, jamais à partir du SSE d’n8n. Maintenant une déconnexion ne fait que couper la lecture, l’exécution continue, et au rechargement le client se réabonne et rattrape le retard à partir de la réponse partiellement stockée. C’est la réponse pour avoir les deux : le travail est lié à la tâche, le flux est lié au stockage.
-
Si la fluidité au niveau des tokens est vraiment importante, faites le streaming du modèle dans un petit streamer en dehors d’n8n (une petite fonction edge qui envoie les tokens du modèle au client et publie la transcription finale vers n8n pour l’écriture en mémoire durable et tous les outils). n8n reste le système d’autorité, la fonction edge n’est que le tuyau.
Un dernier point, dans l’esprit de la remarque d’achamm sur les outils avec effets secondaires : gardez chaque effet secondaire, envoyez un e-mail, écrivez dans un CRM, tout ce qui coûte de l’argent, contrôlé par le tour engagé et identifié par l’ID du tour, pour qu’un tour relancé ou inachevé ne puisse pas le déclencher deux fois. Le streaming ne devrait jamais être ce qui décide si un effet secondaire s’est produit.
Vous n’avez donc pas vraiment à choisir. Liez l’exécution à une tâche durable, liez le flux à un canal externe, et la déconnexion du client cesse d’être un problème.
Salut 
Je pense que je comprends le problème — c’est un cas limite assez courant avec n8n AI Agent + streaming quand la connexion client se coupe (actualisation du navigateur / reconnexion).
Ce qui se passe ici, c’est essentiellement :
le cycle de vie du stream est trop étroitement lié au contexte d’exécution, donc quand le frontend se déconnecte, l’exécution du backend soit se coupe, soit se réhydrate incorrectement.
Je traiterais cela comme deux cycles de vie actuellement couplés :
-
cycle de vie du streaming client
La connexion navigateur/client souhaite recevoir des jetons/événements partiels maintenant.
-
cycle de vie de l’exécution serveur
L’exécution de l’agent peut avoir besoin de se terminer même si le client se déconnecte.
Si ceux-ci sont liés à la même connexion HTTP, une déconnexion peut devenir un signal d’annulation d’exécution. Pour les agents de longue durée, je découperais généralement :
- la requête démarre un job et retourne un job_id ;
- le workflow côté serveur continue indépendamment ;
- le point de terminaison de streaming s’abonne uniquement aux événements du job ;
- si le streaming se déconnecte, le job continue de s’exécuter ;
- le client peut se reconnecter avec le job_id et récupérer le statut/événements/résultat actuels ;
- les états terminaux sont success, failed, cancelled_by_user, timed_out.
La distinction importante est « le client a disparu » par rapport à « l’utilisateur a intentionnellement annulé ». Ce sont des états qui devraient être séparés.
Si le chemin de streaming actuel de n8n lie la déconnexion à l’abandon, le motif plus sûr consiste à placer l’agent de longue durée derrière une couche de job durable et à traiter le streaming comme un observateur, non comme le propriétaire de l’exécution.
Une question non sensible : avez-vous besoin que le navigateur reçoive chaque jeton intermédiaire, ou est-il suffisant de streamer les statuts/événements et de récupérer le résultat final lorsque le job se termine ?
Bienvenue @sawsew467 !
C’est une contrainte architecturale actuelle de n8n : quand le streaming est activé, le cycle de vie de l’exécution est lié à la connexion push, donc une déconnexion signale un abandon. Il n’existe pas actuellement de paramètre intégré pour les découpler.
Le modèle fonctionnel le plus proche dans n8n aujourd’hui : utiliser un Webhook régulier (sans streaming) comme point d’entrée, retourner immédiatement un job_id au client en utilisant le nœud « Respond to Webhook », puis déclencher le travail réel de l’agent comme un sous-workflow en utilisant « Execute Workflow » configuré en mode « Run in Background ». Le client interroge un second webhook GET avec le job_id pour récupérer le résultat une fois qu’il est écrit dans une base de données ou un magasin de données statique. Vous perdez le streaming de tokens en temps réel, mais l’exécution de l’agent se termine quel que soit l’état du client - ce qui semble être ce dont vous avez vraiment besoin ici.