La plupart de ce fil de discussion contient des conseils génériques en matière d’observabilité. Les parties spécifiques à n8n sont là où se trouvent réellement les réponses à tes cinq questions, donc :
La profondeur de la file d’attente et la charge par locataire sont déjà exposées — tu n’as pas à les construire. n8n fournit un endpoint Prometheus désactivé par défaut : N8N_METRICS=true te donne /metrics sur le serveur principal. Les drapeaux qui importent dans ton cas sont N8N_METRICS_INCLUDE_QUEUE_METRICS (c’est ta queue_depth), N8N_METRICS_INCLUDE_WORKFLOW_ID_LABEL et N8N_METRICS_INCLUDE_NODE_TYPE_LABEL (séries par workflow et par type de nœud, ce qui fait que « quel locataire génère le plus de charge » et « quelle API externe est lente » deviennent une seule requête PromQL au lieu d’un projet de journalisation). Récupère-la dans ce que tu exécutes déjà. Surveille la cardinalité si tu as beaucoup de workflows — le libellé workflow-id est ce qui le rend utile et aussi ce qui le rend coûteux.
Ta métrique error_rate te mentira, et c’est celle-ci qui pose problème à l’échelle multi-locataire. Une exécution n8n se termine avec le statut success dans de nombreux cas où rien ne s’est réellement passé : un nœud qui retourne zéro élément transmet simplement zéro élément en aval et tout ce qui suit se désactive silencieusement ; une condition IF sans branche correspondante ; la sortie done d’une Split In Batches que personne n’a connectée. L’exécution est verte, le taux d’erreur reste plat, et les données du locataire n’ont tout simplement pas bougé. Ne surveille donc pas seulement les erreurs — affirme les résultats. Émets un comptage d’éléments à la fin de chaque workflow de locataire et déclenche une alerte sur processed == 0 quand zéro n’est pas un résultat légitime. Le succès silencieux est le mode de défaillance qui atteint tes clients avant d’atteindre ton tableau de bord.
« Détecter les problèmes avant que les clients ne les remarquent » nécessite un interrupteur de sécurité, pas une alerte. L’Error Trigger / Error Workflow est le bon crochet d’alerte par locataire — définis-le par workflow, et mets assez d’informations dans la charge pour que ce soit exploitable ($execution.id, le nom du workflow, le nœud défaillant et les données du dernier nœud ; une alerte qui dit juste « le workflow a échoué » te coûte une session de débogage à chaque fois). Mais note ce qu’il ne peut structurellement pas faire : l’Error Trigger ne se déclenche jamais pour une exécution qui n’a jamais commencé. Un déclencheur d’horaire bloqué, un worker coincé, un workflow que quelqu’un a désactivé — tous produisent du silence, et le silence ressemble exactement à « tout va bien ». La correction est inversée : fais en sorte que chaque workflow de locataire signale sa fin à un watchdog, et déclenche une alerte quand le signal est absent. Cette seule vérification détecte toute la classe de défaillances que tes journaux ne peuvent pas voir par construction.
Ton goulot d’étranglement est probablement execution_entity. À volume multi-locataire, la table de données d’exécution est ce qui ralentit Postgres, et elle augmente discrètement. EXECUTIONS_DATA_PRUNE=true avec un vrai EXECUTIONS_DATA_MAX_AGE et EXECUTIONS_DATA_PRUNE_MAX_COUNT, et pour les locataires à haut volume, envisage EXECUTIONS_DATA_SAVE_ON_SUCCESS=none — conserver les charges complètes de succès pour chaque exécution est un coût important pour des données que tu n’ouvriras jamais. Nettoie avant d’optimiser les requêtes ; beaucoup de « n8n est lent » s’avère être cela.
Une chose utile à décider tôt puisque tu es multi-locataire : cette table d’exécution contient les charges réelles de tes locataires. Si l’un d’entre eux est dans l’UE, la base de données d’exécution est un lieu de traitement, et la conservation y est une question de conformité, pas seulement une question d’espace disque. Beaucoup moins cher de fixer la politique maintenant que de l’expliquer plus tard.