Skip to main content
Glama
PerformanceValidator.ts9.57 kB
import WorkflowValidator from '../resources/WorkflowValidator.js'; /** * Validateur pour les aspects de performance dans les workflows n8n */ class PerformanceValidator implements WorkflowValidator { /** * Valide les aspects de performance dans un workflow n8n * @param workflow Les données du workflow à valider * @param strictness Le niveau de rigueur de la validation * @returns Résultat de la validation avec les problèmes détectés */ validate(workflow: any, strictness: 'low' | 'medium' | 'high') { const issues: Array<{ message: string; recommendation: string; severity: 'low' | 'medium' | 'high'; location?: string; }> = []; // Vérifier la complexité du workflow this.checkWorkflowComplexity(workflow, issues, strictness); // Vérifier les nœuds pour les problèmes de performance if (workflow.nodes && Array.isArray(workflow.nodes)) { workflow.nodes.forEach((node: any) => { // Vérifier les boucles this.checkLoops(node, workflow, issues, strictness); // Vérifier les opérations de traitement de données this.checkDataProcessing(node, issues, strictness); // Vérifier les appels HTTP this.checkHttpCalls(node, issues, strictness); }); } // Vérifier les connexions entre les nœuds this.checkNodeConnections(workflow, issues, strictness); return { valid: issues.length === 0, issues, }; } /** * Vérifie la complexité globale du workflow */ private checkWorkflowComplexity(workflow: any, issues: any[], strictness: string): void { if (!workflow.nodes || !Array.isArray(workflow.nodes)) { return; } // Vérifier le nombre de nœuds const nodeCount = workflow.nodes.length; if (strictness === 'high' && nodeCount > 30) { issues.push({ message: `Le workflow contient un grand nombre de nœuds (${nodeCount})`, recommendation: 'Envisagez de diviser le workflow en plusieurs workflows plus petits pour améliorer la maintenabilité et les performances', severity: 'medium', }); } else if (strictness === 'medium' && nodeCount > 50) { issues.push({ message: `Le workflow contient un très grand nombre de nœuds (${nodeCount})`, recommendation: 'Divisez le workflow en plusieurs workflows plus petits pour améliorer la maintenabilité et les performances', severity: 'medium', }); } // Vérifier la profondeur du workflow (chemin le plus long) if (workflow.connections) { const depth = this.calculateWorkflowDepth(workflow); if ((strictness === 'high' && depth > 15) || (strictness === 'medium' && depth > 25)) { issues.push({ message: `Le workflow a une profondeur élevée (${depth} nœuds dans le chemin le plus long)`, recommendation: 'Réduisez la profondeur du workflow en le divisant en sous-workflows ou en optimisant la logique', severity: 'low', }); } } } /** * Calcule la profondeur maximale du workflow (chemin le plus long) */ private calculateWorkflowDepth(workflow: any): number { // Implémentation simplifiée pour estimer la profondeur // Dans une implémentation complète, on utiliserait un algorithme de parcours de graphe // Identifier les nœuds de départ (triggers) const startNodes = workflow.nodes.filter((node: any) => (node.type || '').toLowerCase().includes('trigger') ).map((node: any) => node.id); // Si aucun nœud de départ n'est trouvé, utiliser le premier nœud const rootNodes = startNodes.length > 0 ? startNodes : [workflow.nodes[0]?.id]; // Estimation de la profondeur basée sur le nombre de connexions let depth = 0; if (workflow.connections) { // Compter le nombre de connexions pour estimer la profondeur const connectionCount = Object.keys(workflow.connections).length; // Estimation grossière: chaque connexion ajoute potentiellement un niveau de profondeur depth = Math.min(connectionCount, workflow.nodes.length); } return depth; } /** * Vérifie les nœuds de boucle pour les problèmes de performance */ private checkLoops(node: any, workflow: any, issues: any[], strictness: string): void { // Identifier les nœuds de boucle if ((node.type || '').toLowerCase().includes('loop') || (node.type || '').toLowerCase().includes('each') || (node.type || '').toLowerCase().includes('split')) { // Vérifier si la boucle a une limite if (!node.parameters?.limit && strictness !== 'low') { issues.push({ message: `Le nœud de boucle "${node.name}" n'a pas de limite définie`, recommendation: 'Définissez une limite pour éviter les boucles infinies ou le traitement d\'un trop grand nombre d\'éléments', severity: 'medium', location: node.id, }); } // Vérifier si la boucle traite potentiellement un grand nombre d'éléments if (node.parameters?.batchSize && node.parameters.batchSize > 100 && strictness === 'high') { issues.push({ message: `Le nœud de boucle "${node.name}" traite de grands lots (taille: ${node.parameters.batchSize})`, recommendation: 'Réduisez la taille des lots pour améliorer les performances et éviter les timeouts', severity: 'low', location: node.id, }); } } } /** * Vérifie les nœuds de traitement de données pour les problèmes de performance */ private checkDataProcessing(node: any, issues: any[], strictness: string): void { // Vérifier les nœuds de transformation de données if ((node.type || '').toLowerCase().includes('set') || (node.type || '').toLowerCase().includes('function') || (node.type || '').toLowerCase().includes('transform')) { // Vérifier le code des nœuds Function pour les opérations coûteuses if (node.parameters?.functionCode || node.parameters?.code) { const code = node.parameters.functionCode || node.parameters.code; // Vérifier les boucles imbriquées if (typeof code === 'string' && (code.match(/for\s*\(/g) || []).length > 1 && strictness !== 'low') { issues.push({ message: `Le nœud "${node.name}" contient des boucles imbriquées qui peuvent affecter les performances`, recommendation: 'Évitez les boucles imbriquées ou optimisez l\'algorithme pour améliorer les performances', severity: 'medium', location: node.id, }); } // Vérifier les opérations sur de grands tableaux if (typeof code === 'string' && (code.includes('.map(') || code.includes('.filter(') || code.includes('.reduce(')) && code.includes('items.json') && strictness === 'high') { issues.push({ message: `Le nœud "${node.name}" effectue des opérations sur des tableaux potentiellement grands`, recommendation: 'Envisagez d\'utiliser des nœuds de traitement par lots pour les grands ensembles de données', severity: 'low', location: node.id, }); } } } } /** * Vérifie les nœuds HTTP pour les problèmes de performance */ private checkHttpCalls(node: any, issues: any[], strictness: string): void { if ((node.type || '').toLowerCase().includes('http')) { // Vérifier si le nœud HTTP a un timeout configuré if (!node.parameters?.timeout && strictness !== 'low') { issues.push({ message: `Le nœud HTTP "${node.name}" n'a pas de timeout configuré`, recommendation: 'Configurez un timeout pour éviter que le workflow ne reste bloqué sur des requêtes lentes', severity: 'low', location: node.id, }); } // Vérifier les requêtes HTTP dans une boucle // Cette vérification nécessiterait une analyse des connexions entre les nœuds // Implémentation simplifiée pour l'exemple } } /** * Vérifie les connexions entre les nœuds pour les problèmes de performance */ private checkNodeConnections(workflow: any, issues: any[], strictness: string): void { if (!workflow.nodes || !Array.isArray(workflow.nodes) || !workflow.connections) { return; } // Vérifier les nœuds avec de nombreuses connexions sortantes (fan-out) Object.entries(workflow.connections).forEach(([nodeId, connections]: [string, any]) => { const connectionCount = Object.values(connections).flat().length; if (connectionCount > 5 && strictness !== 'low') { const nodeName = workflow.nodes.find((n: any) => n.id === nodeId)?.name || 'Inconnu'; issues.push({ message: `Le nœud "${nodeName}" a un grand nombre de connexions sortantes (${connectionCount})`, recommendation: 'Un grand nombre de connexions sortantes peut affecter les performances. Envisagez de restructurer le workflow', severity: 'low', location: nodeId, }); } }); // Vérifier les chemins parallèles excessifs // Cette vérification nécessiterait une analyse plus complexe du graphe de workflow // Implémentation simplifiée pour l'exemple } } export default PerformanceValidator;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lowprofix/n8n-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server