5 técnicas de JavaScript para recuperação de erros de fluxo de trabalho
Explore técnicas essenciais de JavaScript para uma recuperação eficaz de erros em fluxos de trabalho, garantindo estabilidade e resiliência em processos de automação.

A recuperação de erros é a espinha dorsal de qualquer fluxo de trabalho automatizado confiável. JavaScript, com sua natureza assíncrona e orientada a eventos, oferece ferramentas poderosas para garantir que os fluxos de trabalho possam lidar com interrupções como timeouts de API ou inconsistências de dados. Ao implementar técnicas como blocos try-catch, classes de erro personalizadas e mecanismos de repetição, você pode proteger seus processos contra falhas e manter a estabilidade do sistema. Plataformas como Nó latente tornar isso ainda mais fácil, fornecendo mais de 300 integrações e recursos de script personalizados para construir sistemas resilientes fluxos de trabalho de automação adaptado às suas necessidades.
Vamos analisar cinco técnicas essenciais para recuperação de erros em fluxos de trabalho JavaScript e como você pode aplicá-las de forma eficaz.
JavaScript Dicas e truques para tratamento e rastreamento de erros
1. Try-Catch e tratamento de erros assíncronos
O tentar pegar O bloco atua como sua principal proteção contra interrupções no fluxo de trabalho, capturando erros antes que eles se propaguem e causem problemas generalizados na sua automação. Embora a estrutura básica try-catch funcione bem para código síncrono, fluxos de trabalho assíncronos exigem uma abordagem mais personalizada.
Para operações síncronas, o bloco try-catch padrão é direto e eficaz. No entanto, automações que envolvem chamadas de API, consultas a bancos de dados ou manipulação de arquivos geralmente dependem de fluxos de trabalho assíncronos. Nesses casos, rejeições de promessas não tratadas podem encerrar todo o processo inesperadamente, tornando essencial um tratamento de erros robusto.
<span class="hljs-comment">// Basic synchronous error handling</span>
<span class="hljs-keyword">function</span> <span class="hljs-title function_">processWorkflowData</span>(<span class="hljs-params">data</span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">const</span> result = <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">parse</span>(data);
<span class="hljs-keyword">return</span> <span class="hljs-title function_">validateBusinessRules</span>(result);
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Data processing failed:'</span>, error.<span class="hljs-property">message</span>);
<span class="hljs-keyword">return</span> { <span class="hljs-attr">status</span>: <span class="hljs-string">'error'</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">'Invalid data format'</span> };
}
}
Para fluxos de trabalho assíncronos, Utilizando async/await fornece uma maneira mais limpa e legível de lidar com promessas de forma eficaz.
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">executeWorkflowStep</span>(<span class="hljs-params">apiEndpoint, payload</span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(apiEndpoint, {
<span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
<span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
<span class="hljs-attr">body</span>: <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(payload)
});
<span class="hljs-keyword">if</span> (!response.<span class="hljs-property">ok</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">`API call failed: <span class="hljs-subst">${response.status}</span>`</span>);
}
<span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.<span class="hljs-title function_">json</span>();
<span class="hljs-keyword">return</span> { <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>, data };
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">success</span>: <span class="hljs-literal">false</span>,
<span class="hljs-attr">error</span>: error.<span class="hljs-property">message</span>,
<span class="hljs-attr">timestamp</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>().<span class="hljs-title function_">toISOString</span>()
};
}
}
Alternativamente, Cadeias Promise.catch() pode ser usado para lidar com erros em fluxos de trabalho que dependem fortemente de promessas encadeadas.
<span class="hljs-keyword">function</span> <span class="hljs-title function_">processWorkflowChain</span>(<span class="hljs-params">inputData</span>) {
<span class="hljs-keyword">return</span> <span class="hljs-title function_">validateInput</span>(inputData)
.<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">data</span> =></span> <span class="hljs-title function_">transformData</span>(data))
.<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">transformed</span> =></span> <span class="hljs-title function_">saveToDatabase</span>(transformed))
.<span class="hljs-title function_">then</span>(<span class="hljs-function"><span class="hljs-params">saved</span> =></span> <span class="hljs-title function_">notifyCompletion</span>(saved))
.<span class="hljs-title function_">catch</span>(<span class="hljs-function"><span class="hljs-params">error</span> =></span> {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Workflow chain failed:'</span>, error);
<span class="hljs-keyword">return</span> { <span class="hljs-attr">status</span>: <span class="hljs-string">'failed'</span>, <span class="hljs-attr">step</span>: error.<span class="hljs-property">step</span> || <span class="hljs-string">'unknown'</span> };
});
}
Ao trabalhar com Fluxos de trabalho do Latenode, essas técnicas de tratamento de erros podem ser integradas a nós JavaScript personalizados. Isso ajuda a isolar falhas e garante que suas automações permaneçam estáveis, mesmo ao conectar vários serviços. Ao encapsular chamadas de API e transformações de dados em blocos try-catch, você pode evitar que falhas pontuais interrompam todo o fluxo de trabalho. Isso é particularmente útil ao gerenciar integrações complexas na extensa biblioteca do Latenode, com mais de 300 serviços, onde problemas de rede ou inatividade temporária do serviço podem prejudicar sua automação.
Para adicionar uma camada extra de resiliência, manipuladores de erros globais podem detectar erros que escapam de blocos try-catch locais. Esses manipuladores garantem que falhas inesperadas sejam registradas e podem acionar mecanismos de recuperação.
<span class="hljs-comment">// Global unhandled promise rejection handler</span>
process.<span class="hljs-title function_">on</span>(<span class="hljs-string">'unhandledRejection'</span>, <span class="hljs-function">(<span class="hljs-params">reason, promise</span>) =></span> {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Unhandled Promise Rejection:'</span>, reason);
<span class="hljs-comment">// Log error or trigger alert</span>
<span class="hljs-title function_">logErrorToMonitoring</span>({
<span class="hljs-attr">type</span>: <span class="hljs-string">'unhandledRejection'</span>,
<span class="hljs-attr">reason</span>: reason.<span class="hljs-title function_">toString</span>(),
<span class="hljs-attr">timestamp</span>: <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>()
});
});
Para melhores estratégias de recuperação, concentre-se em capturar erros em operações específicas, em vez de funções inteiras. Essa abordagem direcionada permite implementar planos de recuperação adaptados à natureza e à localização de cada erro. A seguir, exploraremos como classes de erro personalizadas podem aprimorar esse processo, fornecendo mais contexto para o gerenciamento de erros.
2. Classes de erro personalizadas para recuperação contextual
As classes de erro personalizadas trazem clareza ao tratamento de erros, transformando erros genéricos em objetos ricos em contextoIsso permite que os fluxos de trabalho respondam de forma inteligente com base no tipo específico de falha. Embora os erros padrão do JavaScript ofereçam detalhes limitados, as classes de erro personalizadas categorizam os problemas, facilitando a aplicação de estratégias de recuperação direcionadas.
<span class="hljs-comment">// Base custom error class</span>
<span class="hljs-keyword">class</span> <span class="hljs-title class_">WorkflowError</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">Error</span> {
<span class="hljs-title function_">constructor</span>(<span class="hljs-params">message, code, recoverable = <span class="hljs-literal">true</span></span>) {
<span class="hljs-variable language_">super</span>(message);
<span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = <span class="hljs-variable language_">this</span>.<span class="hljs-property">constructor</span>.<span class="hljs-property">name</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">code</span> = code;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">recoverable</span> = recoverable;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">timestamp</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>().<span class="hljs-title function_">toISOString</span>();
<span class="hljs-variable language_">this</span>.<span class="hljs-property">context</span> = {};
}
<span class="hljs-title function_">addContext</span>(<span class="hljs-params">key, value</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">context</span>[key] = value;
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>;
}
}
<span class="hljs-comment">// Specific error types for different failure scenarios</span>
<span class="hljs-keyword">class</span> <span class="hljs-title class_">NetworkError</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">WorkflowError</span> {
<span class="hljs-title function_">constructor</span>(<span class="hljs-params">message, statusCode, endpoint</span>) {
<span class="hljs-variable language_">super</span>(message, <span class="hljs-string">'NETWORK_ERROR'</span>, <span class="hljs-literal">true</span>);
<span class="hljs-variable language_">this</span>.<span class="hljs-property">statusCode</span> = statusCode;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">endpoint</span> = endpoint;
}
}
<span class="hljs-keyword">class</span> <span class="hljs-title class_">ValidationError</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">WorkflowError</span> {
<span class="hljs-title function_">constructor</span>(<span class="hljs-params">message, field, value</span>) {
<span class="hljs-variable language_">super</span>(message, <span class="hljs-string">'VALIDATION_ERROR'</span>, <span class="hljs-literal">false</span>);
<span class="hljs-variable language_">this</span>.<span class="hljs-property">field</span> = field;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">invalidValue</span> = value;
}
}
<span class="hljs-keyword">class</span> <span class="hljs-title class_">RateLimitError</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">WorkflowError</span> {
<span class="hljs-title function_">constructor</span>(<span class="hljs-params">message, retryAfter</span>) {
<span class="hljs-variable language_">super</span>(message, <span class="hljs-string">'RATE_LIMIT'</span>, <span class="hljs-literal">true</span>);
<span class="hljs-variable language_">this</span>.<span class="hljs-property">retryAfter</span> = retryAfter;
}
}
Com essas classes personalizadas, os fluxos de trabalho podem identificar tipos de erros e aplicar métodos de recuperação personalizados. Por exemplo, erros de rede podem acionar uma nova tentativa, erros de validação podem solicitar correção de dados e erros de limite de taxa podem atrasar solicitações futuras de forma inteligente.
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">executeWorkflowWithRecovery</span>(<span class="hljs-params">operation, data</span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-title function_">operation</span>(data);
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-comment">// Handle different error types with specific recovery strategies</span>
<span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">NetworkError</span>) {
<span class="hljs-keyword">if</span> (error.<span class="hljs-property">statusCode</span> >= <span class="hljs-number">500</span>) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Server error detected, retrying in 5 seconds...`</span>);
<span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">5000</span>));
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-title function_">operation</span>(data); <span class="hljs-comment">// Retry once for server errors</span>
}
<span class="hljs-keyword">throw</span> error; <span class="hljs-comment">// Client errors (4xx) are not retryable</span>
}
<span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">RateLimitError</span>) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Rate limited, waiting <span class="hljs-subst">${error.retryAfter}</span> seconds`</span>);
<span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> <span class="hljs-built_in">setTimeout</span>(resolve, error.<span class="hljs-property">retryAfter</span> * <span class="hljs-number">1000</span>));
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-title function_">operation</span>(data);
}
<span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">ValidationError</span>) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">`Data validation failed for field: <span class="hljs-subst">${error.field}</span>`</span>);
<span class="hljs-comment">// Log for manual review, don't retry</span>
<span class="hljs-keyword">return</span> { <span class="hljs-attr">status</span>: <span class="hljs-string">'failed'</span>, <span class="hljs-attr">reason</span>: <span class="hljs-string">'invalid_data'</span>, <span class="hljs-attr">field</span>: error.<span class="hljs-property">field</span> };
}
<span class="hljs-comment">// Unknown error type - handle generically</span>
<span class="hljs-keyword">throw</span> error;
}
}
In Integrações de API, erros personalizados ajudam a padronizar respostas diversas em formatos claros e acionáveis.
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">callExternalAPI</span>(<span class="hljs-params">endpoint, payload</span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetch</span>(endpoint, {
<span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
<span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
<span class="hljs-attr">body</span>: <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(payload)
});
<span class="hljs-keyword">if</span> (response.<span class="hljs-property">status</span> === <span class="hljs-number">429</span>) {
<span class="hljs-keyword">const</span> retryAfter = <span class="hljs-built_in">parseInt</span>(response.<span class="hljs-property">headers</span>.<span class="hljs-title function_">get</span>(<span class="hljs-string">'Retry-After'</span>)) || <span class="hljs-number">60</span>;
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RateLimitError</span>(<span class="hljs-string">'API rate limit exceeded'</span>, retryAfter);
}
<span class="hljs-keyword">if</span> (response.<span class="hljs-property">status</span> >= <span class="hljs-number">500</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">NetworkError</span>(
<span class="hljs-string">`Server error: <span class="hljs-subst">${response.statusText}</span>`</span>,
response.<span class="hljs-property">status</span>,
endpoint
);
}
<span class="hljs-keyword">if</span> (!response.<span class="hljs-property">ok</span>) {
<span class="hljs-keyword">const</span> errorData = <span class="hljs-keyword">await</span> response.<span class="hljs-title function_">json</span>();
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ValidationError</span>(
errorData.<span class="hljs-property">message</span> || <span class="hljs-string">'Request validation failed'</span>,
errorData.<span class="hljs-property">field</span>,
errorData.<span class="hljs-property">value</span>
);
}
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> response.<span class="hljs-title function_">json</span>();
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">WorkflowError</span>) {
<span class="hljs-keyword">throw</span> error; <span class="hljs-comment">// Re-throw custom errors as-is</span>
}
<span class="hljs-comment">// Convert generic errors to custom format</span>
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">NetworkError</span>(
<span class="hljs-string">`Network request failed: <span class="hljs-subst">${error.message}</span>`</span>,
<span class="hljs-number">0</span>,
endpoint
);
}
}
Ao trabalhar com Nó latente, classes de erro personalizadas tornam-se particularmente valiosas para gerenciar fluxos de trabalho complexos que envolvem múltiplos serviços. Por exemplo, você pode definir tipos de erro especializados para problemas de conexão com o banco de dados, problemas de autenticação ou erros de transformação de dados. Cada tipo de erro pode ter sua própria lógica de recuperação, garantindo uma execução tranquila do fluxo de trabalho.
<span class="hljs-comment">// Latenode-specific error handling for multi-service workflows</span>
<span class="hljs-keyword">class</span> <span class="hljs-title class_">IntegrationError</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">WorkflowError</span> {
<span class="hljs-title function_">constructor</span>(<span class="hljs-params">message, service, operation</span>) {
<span class="hljs-variable language_">super</span>(message, <span class="hljs-string">'INTEGRATION_ERROR'</span>, <span class="hljs-literal">true</span>);
<span class="hljs-variable language_">this</span>.<span class="hljs-property">service</span> = service;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">operation</span> = operation;
}
}
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">processLatenodeWorkflow</span>(<span class="hljs-params">data</span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-comment">// Step 1: Validate incoming data</span>
<span class="hljs-keyword">const</span> validated = <span class="hljs-title function_">validateWorkflowData</span>(data);
<span class="hljs-comment">// Step 2: Process through multiple services</span>
<span class="hljs-keyword">const</span> processed = <span class="hljs-keyword">await</span> <span class="hljs-title function_">callExternalAPI</span>(<span class="hljs-string">'/api/transform'</span>, validated);
<span class="hljs-comment">// Step 3: Store results</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-title function_">saveToDatabase</span>(processed);
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">ValidationError</span>) {
<span class="hljs-comment">// Send to error queue for manual review</span>
<span class="hljs-keyword">await</span> <span class="hljs-title function_">logToErrorQueue</span>({
<span class="hljs-attr">type</span>: <span class="hljs-string">'validation_failed'</span>,
<span class="hljs-attr">data</span>: data,
<span class="hljs-attr">error</span>: error.<span class="hljs-property">message</span>,
<span class="hljs-attr">field</span>: error.<span class="hljs-property">field</span>
});
<span class="hljs-keyword">return</span> { <span class="hljs-attr">status</span>: <span class="hljs-string">'queued_for_review'</span> };
}
<span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">IntegrationError</span>) {
<span class="hljs-comment">// Attempt alternative service or fallback</span>
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`<span class="hljs-subst">${error.service}</span> failed, trying fallback method`</span>);
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-title function_">executeWorkflowFallback</span>(data);
}
<span class="hljs-keyword">throw</span> error; <span class="hljs-comment">// Unhandled error types bubble up</span>
}
}
Classes de erro personalizadas também aprimoram o registro de erros, facilitando o rastreamento e a resolução de problemas.
<span class="hljs-comment">// Enhanced error logging with custom classes</span>
<span class="hljs-keyword">function</span> <span class="hljs-title function_">logWorkflowError</span>(<span class="hljs-params">error</span>) {
<span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">WorkflowError</span>) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Workflow Error Details:'</span>, {
<span class="hljs-attr">type</span>: error.<span class="hljs-property">name</span>,
<span class="hljs-attr">code</span>: error.<span class="hljs-property">code</span>,
<span class="hljs-attr">message</span>: error.<span class="hljs-property">message</span>,
<span class="hljs-attr">recoverable</span>: error.<span class="hljs-property">recoverable</span>,
<span class="hljs-attr">timestamp</span>: error.<span class="hljs-property">timestamp</span>,
<span class="hljs-attr">context</span>: error.<span class="hljs-property">context</span>
});
} <span class="hljs-keyword">else</span> {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Unexpected Error:'</span>, error);
}
}
3. Relançamento de erros e enriquecimento de contexto
O relançamento de erros é uma técnica que refina o tratamento de erros, preservando o erro original e adicionando contexto relevante. Essa abordagem garante que todo o rastro de erros permaneça intacto, facilitando a identificação da causa raiz e incluindo detalhes específicos do fluxo de trabalho que auxiliam nos esforços de depuração e recuperação.
Em sua essência, esse método envolve a identificação de erros em vários níveis do fluxo de trabalho, enriquecendo-os com contexto adicional e relançando-os. O resultado é uma cadeia de erros detalhada que destaca não apenas o que deu errado, mas também onde, quando e em que condições o problema ocorreu.
<span class="hljs-comment">// Context enrichment wrapper function</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">enrichErrorContext</span>(<span class="hljs-params">operation, context</span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-title function_">operation</span>();
} <span class="hljs-keyword">catch</span> (originalError) {
<span class="hljs-comment">// Create an enriched error with added context</span>
<span class="hljs-keyword">const</span> enrichedError = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">`<span class="hljs-subst">${context.operation}</span> failed: <span class="hljs-subst">${originalError.message}</span>`</span>);
enrichedError.<span class="hljs-property">originalError</span> = originalError;
enrichedError.<span class="hljs-property">context</span> = {
<span class="hljs-attr">timestamp</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>().<span class="hljs-title function_">toISOString</span>(),
<span class="hljs-attr">operation</span>: context.<span class="hljs-property">operation</span>,
<span class="hljs-attr">step</span>: context.<span class="hljs-property">step</span>,
<span class="hljs-attr">data</span>: context.<span class="hljs-property">data</span>,
<span class="hljs-attr">environment</span>: process.<span class="hljs-property">env</span>.<span class="hljs-property">NODE_ENV</span> || <span class="hljs-string">'development'</span>
};
<span class="hljs-comment">// Append the original stack trace for full transparency</span>
enrichedError.<span class="hljs-property">stack</span> = <span class="hljs-string">`<span class="hljs-subst">${enrichedError.stack}</span>Caused by: <span class="hljs-subst">${originalError.stack}</span>`</span>;
<span class="hljs-keyword">throw</span> enrichedError;
}
}
Essa técnica se baseia em práticas padrão de tratamento de erros ao incorporar detalhes acionáveis em cada estágio do fluxo de trabalho.
Exemplo de fluxo de trabalho multicamadas
Considere um fluxo de trabalho multicamadas onde os erros são enriquecidos em cada estágio para capturar informações detalhadas:
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">processDataWorkflow</span>(<span class="hljs-params">inputData</span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-comment">// Layer 1: Data validation</span>
<span class="hljs-keyword">const</span> validatedData = <span class="hljs-keyword">await</span> <span class="hljs-title function_">enrichErrorContext</span>(
<span class="hljs-function">() =></span> <span class="hljs-title function_">validateInputData</span>(inputData),
{
<span class="hljs-attr">operation</span>: <span class="hljs-string">'data_validation'</span>,
<span class="hljs-attr">step</span>: <span class="hljs-number">1</span>,
<span class="hljs-attr">data</span>: { <span class="hljs-attr">recordCount</span>: inputData.<span class="hljs-property">length</span>, <span class="hljs-attr">source</span>: inputData.<span class="hljs-property">source</span> }
}
);
<span class="hljs-comment">// Layer 2: Data transformation</span>
<span class="hljs-keyword">const</span> transformedData = <span class="hljs-keyword">await</span> <span class="hljs-title function_">enrichErrorContext</span>(
<span class="hljs-function">() =></span> <span class="hljs-title function_">transformData</span>(validatedData),
{
<span class="hljs-attr">operation</span>: <span class="hljs-string">'data_transformation'</span>,
<span class="hljs-attr">step</span>: <span class="hljs-number">2</span>,
<span class="hljs-attr">data</span>: { <span class="hljs-attr">inputSize</span>: validatedData.<span class="hljs-property">length</span>, <span class="hljs-attr">transformType</span>: <span class="hljs-string">'normalize'</span> }
}
);
<span class="hljs-comment">// Layer 3: External API call</span>
<span class="hljs-keyword">const</span> apiResult = <span class="hljs-keyword">await</span> <span class="hljs-title function_">enrichErrorContext</span>(
<span class="hljs-function">() =></span> <span class="hljs-title function_">callExternalService</span>(transformedData),
{
<span class="hljs-attr">operation</span>: <span class="hljs-string">'external_api_call'</span>,
<span class="hljs-attr">step</span>: <span class="hljs-number">3</span>,
<span class="hljs-attr">data</span>: { <span class="hljs-attr">endpoint</span>: <span class="hljs-string">'/api/process'</span>, <span class="hljs-attr">payloadSize</span>: transformedData.<span class="hljs-property">length</span> }
}
);
<span class="hljs-keyword">return</span> apiResult;
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-comment">// Add workflow-level context</span>
error.<span class="hljs-property">workflowId</span> = <span class="hljs-title function_">generateWorkflowId</span>();
error.<span class="hljs-property">totalSteps</span> = <span class="hljs-number">3</span>;
error.<span class="hljs-property">failureRate</span> = <span class="hljs-keyword">await</span> <span class="hljs-title function_">calculateRecentFailureRate</span>();
<span class="hljs-keyword">throw</span> error;
}
}
Operações aninhadas e enriquecimento de contexto
Para fluxos de trabalho com operações aninhadas, o enriquecimento de contexto se torna ainda mais poderoso. Ele permite o rastreamento detalhado de erros em vários níveis. Por exemplo, em operações de banco de dados, os erros podem ser capturados e enriquecidos da seguinte forma:
<span class="hljs-keyword">class</span> <span class="hljs-title class_">DatabaseManager</span> {
<span class="hljs-keyword">async</span> <span class="hljs-title function_">executeQuery</span>(<span class="hljs-params">query, params, context = {}</span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">connection</span>.<span class="hljs-title function_">query</span>(query, params);
} <span class="hljs-keyword">catch</span> (dbError) {
<span class="hljs-keyword">const</span> enrichedError = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">`Database query failed: <span class="hljs-subst">${dbError.message}</span>`</span>);
enrichedError.<span class="hljs-property">originalError</span> = dbError;
enrichedError.<span class="hljs-property">queryContext</span> = {
<span class="hljs-attr">query</span>: query.<span class="hljs-title function_">substring</span>(<span class="hljs-number">0</span>, <span class="hljs-number">100</span>) + <span class="hljs-string">'...'</span>, <span class="hljs-comment">// Truncated for logging</span>
<span class="hljs-attr">paramCount</span>: params ? params.<span class="hljs-property">length</span> : <span class="hljs-number">0</span>,
<span class="hljs-attr">connection</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-property">connection</span>.<span class="hljs-property">threadId</span>,
<span class="hljs-attr">database</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-property">connection</span>.<span class="hljs-property">config</span>.<span class="hljs-property">database</span>,
...context
};
<span class="hljs-keyword">throw</span> enrichedError;
}
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">getUserData</span>(<span class="hljs-params">userId, includeHistory = <span class="hljs-literal">false</span></span>) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">const</span> query = includeHistory
? <span class="hljs-string">'SELECT * FROM users u LEFT JOIN user_history h ON u.id = h.user_id WHERE u.id = ?'</span>
: <span class="hljs-string">'SELECT * FROM users WHERE id = ?'</span>;
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">executeQuery</span>(query, [userId], {
<span class="hljs-attr">operation</span>: <span class="hljs-string">'get_user_data'</span>,
<span class="hljs-attr">userId</span>: userId,
<span class="hljs-attr">includeHistory</span>: includeHistory,
<span class="hljs-attr">queryType</span>: <span class="hljs-string">'SELECT'</span>
});
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-comment">// Append user-specific context</span>
error.<span class="hljs-property">userContext</span> = {
<span class="hljs-attr">requestedUserId</span>: userId,
<span class="hljs-attr">includeHistory</span>: includeHistory,
<span class="hljs-attr">timestamp</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>().<span class="hljs-title function_">toISOString</span>()
};
<span class="hljs-keyword">throw</span> error;
}
}
}
Aplicando o enriquecimento de contexto em Nó latente Fluxos de trabalho
Ao integrar vários serviços em Nó latente Em fluxos de trabalho, o enriquecimento de contexto fornece uma visão clara de onde os erros ocorrem, juntamente com os dados específicos que estão sendo processados. Veja um exemplo:
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">executeLatenodeIntegration</span>(<span class="hljs-params">workflowData</span>) {
<span class="hljs-keyword">const</span> workflowId = <span class="hljs-string">`workflow_<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>`</span>;
<span class="hljs-keyword">const</span> startTime = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>();
<span class="hljs-keyword">try</span> {
<span class="hljs-comment">// Step 1: Fetch data from CRM</span>
<span class="hljs-keyword">const</span> crmData = <span class="hljs-keyword">await</span> <span class="hljs-title function_">enrichErrorContext</span>(
<span class="hljs-function">() =></span> <span class="hljs-title function_">fetchFromCRM</span>(workflowData.<span class="hljs-property">crmId</span>),
{
<span class="hljs-attr">operation</span>: <span class="hljs-string">'crm_data_fetch'</span>,
<span class="hljs-attr">step</span>: <span class="hljs-string">'crm_integration'</span>,
<span class="hljs-attr">workflowId</span>: workflowId,
<span class="hljs-attr">service</span>: <span class="hljs-string">'salesforce'</span>
}
);
<span class="hljs-comment">// Step 2: Process with AI</span>
<span class="hljs-keyword">const</span> processedData = <span class="hljs-keyword">await</span> <span class="hljs-title function_">enrichErrorContext</span>(
<span class="hljs-function">() =></span> <span class="hljs-title function_">processWithAI</span>(crmData),
{
<span class="hljs-attr">operation</span>: <span class="hljs-string">'ai_processing'</span>,
<span class="hljs-attr">step</span>: <span class="hljs-string">'ai_analysis'</span>,
<span class="hljs-attr">workflowId</span>: workflowId,
<span class="hljs-attr">service</span>: <span class="hljs-string">'openai_gpt4'</span>,
<span class="hljs-attr">inputTokens</span>: <span class="hljs-title function_">estimateTokens</span>(crmData)
}
);
<span class="hljs-comment">// Step 3: Update database</span>
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-title function_">enrichErrorContext</span>(
<span class="hljs-function">() =></span> <span class="hljs-title function_">updateDatabase</span>(processedData),
{
<span class="hljs-attr">operation</span>: <span class="hljs-string">'database_update'</span>,
<span class="hljs-attr">step</span>: <span class="hljs-string">'data_persistence'</span>,
<span class="hljs-attr">workflowId</span>: workflowId,
<span class="hljs-attr">recordCount</span>: processedData.<span class="hljs-property">length</span>
}
);
<span class="hljs-keyword">return</span> result;
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-comment">// Add overall workflow metadata</span>
error.<span class="hljs-property">workflowMetadata</span> = {
<span class="hljs-attr">workflowId</span>: workflowId,
<span class="hljs-attr">totalExecutionTime</span>: <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>() - startTime,
<span class="hljs-attr">originalInput</span>: workflowData,
<span class="hljs-attr">failurePoint</span>: error.<span class="hljs-property">context</span>?.<span class="hljs-property">step</span> || <span class="hljs-string">'unknown'</span>,
<span class="hljs-attr">retryable</span>: <span class="hljs-title function_">determineIfRetryable</span>(error)
};
<span class="hljs-comment">// Log enriched error details</span>
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">'Workflow failed with enriched context:'</span>, {
<span class="hljs-attr">message</span>: error.<span class="hljs-property">message</span>,
<span class="hljs-attr">context</span>: error.<span class="hljs-property">context</span>,
<span class="hljs-attr">workflowMetadata</span>: error.<span class="hljs-property">workflowMetadata</span>,
<span class="hljs-attr">originalError</span>: error.<span class="hljs-property">originalError</span>?.<span class="hljs-property">message</span>
});
<span class="hljs-keyword">throw</span> error;
}
}
Recuperação Inteligente de Erros
Ao enriquecer os erros com contexto detalhado, você pode tomar decisões informadas sobre como recuperá-los. Por exemplo, você pode tentar novamente uma operação, limpar os dados ou colocar o problema na fila para revisão manual:
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">handleEnrichedError</span>(<span class="hljs-params">error, originalOperation, originalData</span>) {
<span class="hljs-keyword">const</span> context = error.<span class="hljs-property">context</span> || {};
<span class="hljs-keyword">const</span> workflowMetadata = error.<span class="hljs-property">workflowMetadata</span> || {};
<span class="hljs-comment">// Retry for network issues during API calls</span>
<span class="hljs-keyword">if</span> (context.<span class="hljs-property">operation</span> === <span class="hljs-string">'external_api_call'</span> && error.<span class="hljs-property">originalError</span>?.<span class="hljs-property">code</span> === <span class="hljs-string">'ECONNRESET'</span>) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Network error detected in <span class="hljs-subst">${context.step}</span>, retrying...`</span>);
<span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">2000</span>));
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-title function_">originalOperation</span>(originalData);
}
<span class="hljs-comment">// Attempt cleanup for validation errors</span>
<span class="hljs-keyword">if</span> (context.<span class="hljs-property">operation</span> === <span class="hljs-string">'data_validation'</span> && workflowMetadata.<span class="hljs-property">retryable</span>) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Data validation failed, attempting cleanup...'</span>);
<span class="hljs-keyword">const</span> cleanedData = <span class="hljs-keyword">await</span> <span class="hljs-title function_">cleanupData</span>(originalData);
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-title function_">originalOperation</span>(cleanedData);
}
<span class="hljs-comment">// Queue long-running workflows for manual review</span>
<span class="hljs-keyword">if</span> (workflowMetadata.<span class="hljs-property">totalExecutionTime</span> > <span class="hljs-number">30000</span>) { <span class="hljs-comment">// 30 seconds</span>
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Long-running workflow failed, queuing for manual review...'</span>);
<span class="hljs-keyword">await</span> <span class="hljs-title function_">queueForReview</span>({
<span class="hljs-attr">error</span>: error.<span class="hljs-property">message</span>,
<span class="hljs-attr">workflowMetadata</span>: workflowMetadata
});
}
<span class="hljs-keyword">throw</span> error;
}
sbb-itb-23997f1
4. Estratégias automatizadas de repetição e recuo
Mecanismos de repetição automatizados com estratégias de backoff desempenham um papel fundamental na manutenção de fluxos de trabalho resilientes. Esses métodos abordam automaticamente problemas transitórios, como interrupções de rede, limites de taxa ou restrições temporárias de recursos. Eles também ajudam a evitar a sobrecarga do sistema, aumentando gradualmente os atrasos entre as tentativas, dando tempo aos sistemas para se estabilizarem.
Espera exponencial é uma abordagem comum que aumenta o atraso após cada nova tentativa. Esse método garante que os sistemas não fiquem sobrecarregados enquanto ainda tentam a recuperação.
<span class="hljs-keyword">class</span> <span class="hljs-title class_">RetryManager</span> {
<span class="hljs-title function_">constructor</span>(<span class="hljs-params">options = {}</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">maxRetries</span> = options.<span class="hljs-property">maxRetries</span> || <span class="hljs-number">3</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">baseDelay</span> = options.<span class="hljs-property">baseDelay</span> || <span class="hljs-number">1000</span>; <span class="hljs-comment">// 1 second</span>
<span class="hljs-variable language_">this</span>.<span class="hljs-property">maxDelay</span> = options.<span class="hljs-property">maxDelay</span> || <span class="hljs-number">30000</span>; <span class="hljs-comment">// 30 seconds</span>
<span class="hljs-variable language_">this</span>.<span class="hljs-property">backoffMultiplier</span> = options.<span class="hljs-property">backoffMultiplier</span> || <span class="hljs-number">2</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">jitterRange</span> = options.<span class="hljs-property">jitterRange</span> || <span class="hljs-number">0.1</span>; <span class="hljs-comment">// 10% jitter</span>
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">executeWithRetry</span>(<span class="hljs-params">operation, context = {}</span>) {
<span class="hljs-keyword">let</span> lastError;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> attempt = <span class="hljs-number">0</span>; attempt <= <span class="hljs-variable language_">this</span>.<span class="hljs-property">maxRetries</span>; attempt++) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-title function_">operation</span>();
<span class="hljs-comment">// Log successful retries</span>
<span class="hljs-keyword">if</span> (attempt > <span class="hljs-number">0</span>) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Operation succeeded on attempt <span class="hljs-subst">${attempt + <span class="hljs-number">1</span>}</span>`</span>, {
<span class="hljs-attr">context</span>: context,
<span class="hljs-attr">totalAttempts</span>: attempt + <span class="hljs-number">1</span>,
<span class="hljs-attr">recoveryTime</span>: <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>() - context.<span class="hljs-property">startTime</span>
});
}
<span class="hljs-keyword">return</span> result;
} <span class="hljs-keyword">catch</span> (error) {
lastError = error;
<span class="hljs-comment">// Stop retrying if the error is non-retryable or the max attempts are reached</span>
<span class="hljs-keyword">if</span> (!<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">isRetryableError</span>(error) || attempt === <span class="hljs-variable language_">this</span>.<span class="hljs-property">maxRetries</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">createFinalError</span>(error, attempt + <span class="hljs-number">1</span>, context);
}
<span class="hljs-keyword">const</span> delay = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">calculateDelay</span>(attempt);
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">warn</span>(<span class="hljs-string">`Attempt <span class="hljs-subst">${attempt + <span class="hljs-number">1</span>}</span> failed, retrying in <span class="hljs-subst">${delay}</span>ms`</span>, {
<span class="hljs-attr">error</span>: error.<span class="hljs-property">message</span>,
<span class="hljs-attr">context</span>: context,
<span class="hljs-attr">nextDelay</span>: delay
});
<span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">sleep</span>(delay);
}
}
}
<span class="hljs-title function_">calculateDelay</span>(<span class="hljs-params">attempt</span>) {
<span class="hljs-comment">// Exponential backoff with added jitter</span>
<span class="hljs-keyword">const</span> exponentialDelay = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">min</span>(
<span class="hljs-variable language_">this</span>.<span class="hljs-property">baseDelay</span> * <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">pow</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">backoffMultiplier</span>, attempt),
<span class="hljs-variable language_">this</span>.<span class="hljs-property">maxDelay</span>
);
<span class="hljs-keyword">const</span> jitter = exponentialDelay * <span class="hljs-variable language_">this</span>.<span class="hljs-property">jitterRange</span> * (<span class="hljs-title class_">Math</span>.<span class="hljs-title function_">random</span>() * <span class="hljs-number">2</span> - <span class="hljs-number">1</span>);
<span class="hljs-keyword">return</span> <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">round</span>(exponentialDelay + jitter);
}
<span class="hljs-title function_">isRetryableError</span>(<span class="hljs-params">error</span>) {
<span class="hljs-comment">// Handle transient network errors</span>
<span class="hljs-keyword">if</span> (error.<span class="hljs-property">code</span> === <span class="hljs-string">'ECONNRESET'</span> || error.<span class="hljs-property">code</span> === <span class="hljs-string">'ETIMEDOUT'</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
<span class="hljs-comment">// Retry on specific HTTP status codes</span>
<span class="hljs-keyword">if</span> (error.<span class="hljs-property">response</span>?.<span class="hljs-property">status</span>) {
<span class="hljs-keyword">const</span> status = error.<span class="hljs-property">response</span>.<span class="hljs-property">status</span>;
<span class="hljs-keyword">return</span> [<span class="hljs-number">429</span>, <span class="hljs-number">502</span>, <span class="hljs-number">503</span>, <span class="hljs-number">504</span>].<span class="hljs-title function_">includes</span>(status);
}
<span class="hljs-comment">// Check for database connection issues</span>
<span class="hljs-keyword">if</span> (error.<span class="hljs-property">message</span>?.<span class="hljs-title function_">includes</span>(<span class="hljs-string">'connection'</span>) || error.<span class="hljs-property">message</span>?.<span class="hljs-title function_">includes</span>(<span class="hljs-string">'timeout'</span>)) {
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
<span class="hljs-title function_">createFinalError</span>(<span class="hljs-params">originalError, totalAttempts, context</span>) {
<span class="hljs-keyword">const</span> finalError = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">`Operation failed after <span class="hljs-subst">${totalAttempts}</span> attempts: <span class="hljs-subst">${originalError.message}</span>`</span>);
finalError.<span class="hljs-property">originalError</span> = originalError;
finalError.<span class="hljs-property">retryContext</span> = {
<span class="hljs-attr">totalAttempts</span>: totalAttempts,
<span class="hljs-attr">finalAttemptTime</span>: <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>(),
<span class="hljs-attr">context</span>: context,
<span class="hljs-attr">wasRetryable</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">isRetryableError</span>(originalError)
};
<span class="hljs-keyword">return</span> finalError;
}
<span class="hljs-title function_">sleep</span>(<span class="hljs-params">ms</span>) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =></span> <span class="hljs-built_in">setTimeout</span>(resolve, ms));
}
}
Este sistema de repetição integra-se perfeitamente a estruturas mais amplas de recuperação de erros, garantindo estabilidade e eficiência.
Implementação do Padrão do Disjuntor
Para complementar os mecanismos de repetição, o padrão de disjuntor atua como uma proteção contra falhas repetidas. Ao interromper temporariamente as operações quando as taxas de erro excedem os limites aceitáveis, evita falhas em cascata e dá aos sistemas com dificuldades uma chance de se recuperar.
Aqui está um exemplo de como isso pode ser implementado:
<span class="hljs-keyword">class</span> <span class="hljs-title class_">CircuitBreaker</span> {
<span class="hljs-title function_">constructor</span>(<span class="hljs-params">options = {}</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">failureThreshold</span> = options.<span class="hljs-property">failureThreshold</span> || <span class="hljs-number">5</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">recoveryTimeout</span> = options.<span class="hljs-property">recoveryTimeout</span> || <span class="hljs-number">60000</span>; <span class="hljs-comment">// 1 minute</span>
<span class="hljs-variable language_">this</span>.<span class="hljs-property">monitoringWindow</span> = options.<span class="hljs-property">monitoringWindow</span> || <span class="hljs-number">120000</span>; <span class="hljs-comment">// 2 minutes</span>
<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> = <span class="hljs-string">'CLOSED'</span>; <span class="hljs-comment">// Possible states: CLOSED, OPEN, HALF_OPEN</span>
<span class="hljs-variable language_">this</span>.<span class="hljs-property">failureCount</span> = <span class="hljs-number">0</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">lastFailureTime</span> = <span class="hljs-literal">null</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">successCount</span> = <span class="hljs-number">0</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">requestHistory</span> = [];
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">execute</span>(<span class="hljs-params">operation, context = {}</span>) {
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> === <span class="hljs-string">'OPEN'</span>) {
<span class="hljs-keyword">if</span> (<span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>() - <span class="hljs-variable language_">this</span>.<span class="hljs-property">lastFailureTime</span> >= <span class="hljs-variable language_">this</span>.<span class="hljs-property">recoveryTimeout</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> = <span class="hljs-string">'HALF_OPEN'</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">successCount</span> = <span class="hljs-number">0</span>;
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Circuit breaker transitioning to HALF_OPEN state'</span>, { context });
} <span class="hljs-keyword">else</span> {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">`Circuit breaker is OPEN. Service unavailable. Retry after <span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-variable language_">this</span>.lastFailureTime + <span class="hljs-variable language_">this</span>.recoveryTimeout).toLocaleString()}</span>`</span>);
}
}
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-title function_">operation</span>();
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onSuccess</span>(context);
<span class="hljs-keyword">return</span> result;
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">onFailure</span>(error, context);
<span class="hljs-keyword">throw</span> error;
}
}
<span class="hljs-title function_">onSuccess</span>(<span class="hljs-params">context</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">recordRequest</span>(<span class="hljs-literal">true</span>);
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> === <span class="hljs-string">'HALF_OPEN'</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">successCount</span>++;
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">successCount</span> >= <span class="hljs-number">3</span>) { <span class="hljs-comment">// Require three consecutive successes to close the breaker</span>
<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> = <span class="hljs-string">'CLOSED'</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">failureCount</span> = <span class="hljs-number">0</span>;
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Circuit breaker CLOSED after successful recovery'</span>, { context });
}
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> === <span class="hljs-string">'CLOSED'</span>) {
<span class="hljs-comment">// Gradually reduce failure count during normal operation</span>
<span class="hljs-variable language_">this</span>.<span class="hljs-property">failureCount</span> = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">max</span>(<span class="hljs-number">0</span>, <span class="hljs-variable language_">this</span>.<span class="hljs-property">failureCount</span> - <span class="hljs-number">1</span>);
}
}
<span class="hljs-title function_">onFailure</span>(<span class="hljs-params">error, context</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">recordRequest</span>(<span class="hljs-literal">false</span>);
<span class="hljs-variable language_">this</span>.<span class="hljs-property">failureCount</span>++;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">lastFailureTime</span> = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>();
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> === <span class="hljs-string">'HALF_OPEN'</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> = <span class="hljs-string">'OPEN'</span>;
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Circuit breaker OPEN after failure in HALF_OPEN state'</span>, {
<span class="hljs-attr">error</span>: error.<span class="hljs-property">message</span>,
context
});
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> === <span class="hljs-string">'CLOSED'</span> && <span class="hljs-variable language_">this</span>.<span class="hljs-property">failureCount</span> >= <span class="hljs-variable language_">this</span>.<span class="hljs-property">failureThreshold</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span> = <span class="hljs-string">'OPEN'</span>;
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">'Circuit breaker OPEN due to failure threshold exceeded'</span>, {
<span class="hljs-attr">failureCount</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-property">failureCount</span>,
<span class="hljs-attr">threshold</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-property">failureThreshold</span>,
context
});
}
}
<span class="hljs-title function_">recordRequest</span>(<span class="hljs-params">success</span>) {
<span class="hljs-keyword">const</span> now = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>();
<span class="hljs-variable language_">this</span>.<span class="hljs-property">requestHistory</span>.<span class="hljs-title function_">push</span>({ <span class="hljs-attr">timestamp</span>: now, success });
<span class="hljs-comment">// Discard records outside the monitoring window</span>
<span class="hljs-variable language_">this</span>.<span class="hljs-property">requestHistory</span> = <span class="hljs-variable language_">this</span>.<span class="hljs-property">requestHistory</span>.<span class="hljs-title function_">filter</span>(
<span class="hljs-function"><span class="hljs-params">record</span> =></span> now - record.<span class="hljs-property">timestamp</span> <= <span class="hljs-variable language_">this</span>.<span class="hljs-property">monitoringWindow</span>
);
}
<span class="hljs-title function_">getHealthMetrics</span>(<span class="hljs-params"></span>) {
<span class="hljs-keyword">const</span> now = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>();
<span class="hljs-keyword">const</span> recentRequests = <span class="hljs-variable language_">this</span>.<span class="hljs-property">requestHistory</span>.<span class="hljs-title function_">filter</span>(
<span class="hljs-function"><span class="hljs-params">record</span> =></span> now - record.<span class="hljs-property">timestamp</span> <= <span class="hljs-variable language_">this</span>.<span class="hljs-property">monitoringWindow</span>
);
<span class="hljs-keyword">const</span> totalRequests = recentRequests.<span class="hljs-property">length</span>;
<span class="hljs-keyword">const</span> successfulRequests = recentRequests.<span class="hljs-title function_">filter</span>(<span class="hljs-function"><span class="hljs-params">r</span> =></span> r.<span class="hljs-property">success</span>).<span class="hljs-property">length</span>;
<span class="hljs-keyword">const</span> failureRate = totalRequests > <span class="hljs-number">0</span> ? (totalRequests - successfulRequests) / totalRequests : <span class="hljs-number">0</span>;
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">state</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-property">state</span>,
<span class="hljs-attr">failureCount</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-property">failureCount</span>,
totalRequests,
successfulRequests,
<span class="hljs-attr">failureRate</span>: <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">round</span>(failureRate * <span class="hljs-number">100</span>) / <span class="hljs-number">100</span>,
<span class="hljs-attr">lastFailureTime</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-property">lastFailureTime</span> ? <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">lastFailureTime</span>).<span class="hljs-title function_">toLocaleString</span>() : <span class="hljs-string">'N/A'</span>
Essa abordagem garante que sistemas com falhas não sejam sobrecarregados, ao mesmo tempo em que fornece um caminho claro para a recuperação. Juntos, mecanismos de nova tentativa e disjuntores criam uma base sólida para lidar com erros em sistemas distribuídos.
5. Preservação e reversão do estado do fluxo de trabalho
Preservar o estado de um fluxo de trabalho em pontos cruciais permite a recuperação eficaz de erros sem a necessidade de reiniciar todo o processo. Essa abordagem é especialmente valiosa para fluxos de trabalho que envolvem múltiplas interações de sistema, transformações complexas de dados ou tarefas de longa duração, nas quais a execução incompleta pode levar a inconsistências.
Ao salvar snapshots de dados de fluxo de trabalho, estados do sistema e contextos de execução em pontos específicos, os mecanismos de rollback podem restaurar esses estados salvos. Isso garante que os processos possam ser retomados a partir de um ponto estável e confiável. Abaixo, um exemplo de como implementar preservação de estado e rollback em JavaScript:
<span class="hljs-keyword">class</span> <span class="hljs-title class_">WorkflowStateManager</span> {
<span class="hljs-title function_">constructor</span>(<span class="hljs-params">options = {}</span>) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">stateStorage</span> = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Map</span>();
<span class="hljs-variable language_">this</span>.<span class="hljs-property">rollbackStack</span> = [];
<span class="hljs-variable language_">this</span>.<span class="hljs-property">maxStateHistory</span> = options.<span class="hljs-property">maxStateHistory</span> || <span class="hljs-number">10</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">compressionEnabled</span> = options.<span class="hljs-property">compressionEnabled</span> || <span class="hljs-literal">false</span>;
<span class="hljs-variable language_">this</span>.<span class="hljs-property">persistentStorage</span> = options.<span class="hljs-property">persistentStorage</span> || <span class="hljs-literal">null</span>;
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">saveCheckpoint</span>(<span class="hljs-params">checkpointId, workflowData, metadata = {}</span>) {
<span class="hljs-keyword">const</span> checkpoint = {
<span class="hljs-attr">id</span>: checkpointId,
<span class="hljs-attr">timestamp</span>: <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>(),
<span class="hljs-attr">data</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">deepClone</span>(workflowData),
<span class="hljs-attr">metadata</span>: {
...metadata,
<span class="hljs-attr">version</span>: <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">generateVersion</span>(),
<span class="hljs-attr">size</span>: <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(workflowData).<span class="hljs-property">length</span>
}
};
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">compressionEnabled</span> && checkpoint.<span class="hljs-property">metadata</span>.<span class="hljs-property">size</span> > <span class="hljs-number">10000</span>) {
checkpoint.<span class="hljs-property">data</span> = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">compressState</span>(checkpoint.<span class="hljs-property">data</span>);
checkpoint.<span class="hljs-property">compressed</span> = <span class="hljs-literal">true</span>;
}
<span class="hljs-variable language_">this</span>.<span class="hljs-property">stateStorage</span>.<span class="hljs-title function_">set</span>(checkpointId, checkpoint);
<span class="hljs-variable language_">this</span>.<span class="hljs-property">rollbackStack</span>.<span class="hljs-title function_">push</span>(checkpointId);
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">rollbackStack</span>.<span class="hljs-property">length</span> > <span class="hljs-variable language_">this</span>.<span class="hljs-property">maxStateHistory</span>) {
<span class="hljs-keyword">const</span> oldestId = <span class="hljs-variable language_">this</span>.<span class="hljs-property">rollbackStack</span>.<span class="hljs-title function_">shift</span>();
<span class="hljs-variable language_">this</span>.<span class="hljs-property">stateStorage</span>.<span class="hljs-title function_">delete</span>(oldestId);
}
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">persistentStorage</span>) {
<span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">persistentStorage</span>.<span class="hljs-title function_">save</span>(checkpointId, checkpoint);
}
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Checkpoint <span class="hljs-subst">${checkpointId}</span> saved`</span>, {
<span class="hljs-attr">size</span>: checkpoint.<span class="hljs-property">metadata</span>.<span class="hljs-property">size</span>,
<span class="hljs-attr">compressed</span>: checkpoint.<span class="hljs-property">compressed</span> || <span class="hljs-literal">false</span>
});
<span class="hljs-keyword">return</span> checkpoint.<span class="hljs-property">metadata</span>.<span class="hljs-property">version</span>;
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">rollbackToCheckpoint</span>(<span class="hljs-params">checkpointId, options = {}</span>) {
<span class="hljs-keyword">const</span> checkpoint = <span class="hljs-variable language_">this</span>.<span class="hljs-property">stateStorage</span>.<span class="hljs-title function_">get</span>(checkpointId);
<span class="hljs-keyword">if</span> (!checkpoint) {
<span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">persistentStorage</span>) {
<span class="hljs-keyword">const</span> persistedCheckpoint = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">persistentStorage</span>.<span class="hljs-title function_">load</span>(checkpointId);
<span class="hljs-keyword">if</span> (persistedCheckpoint) {
<span class="hljs-variable language_">this</span>.<span class="hljs-property">stateStorage</span>.<span class="hljs-title function_">set</span>(checkpointId, persistedCheckpoint);
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">executeRollback</span>(persistedCheckpoint, options);
}
}
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">`Checkpoint <span class="hljs-subst">${checkpointId}</span> not found`</span>);
}
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">executeRollback</span>(checkpoint, options);
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">executeRollback</span>(<span class="hljs-params">checkpoint, options</span>) {
<span class="hljs-keyword">const</span> rollbackStart = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>();
<span class="hljs-keyword">let</span> removedCount = <span class="hljs-number">0</span>;
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">let</span> restoredData = checkpoint.<span class="hljs-property">data</span>;
<span class="hljs-keyword">if</span> (checkpoint.<span class="hljs-property">compressed</span>) {
restoredData = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">decompressState</span>(checkpoint.<span class="hljs-property">data</span>);
}
<span class="hljs-keyword">if</span> (options.<span class="hljs-property">cleanupOperations</span>) {
<span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">executeCleanupOperations</span>(options.<span class="hljs-property">cleanupOperations</span>);
}
<span class="hljs-keyword">const</span> targetIndex = <span class="hljs-variable language_">this</span>.<span class="hljs-property">rollbackStack</span>.<span class="hljs-title function_">indexOf</span>(checkpoint.<span class="hljs-property">id</span>);
<span class="hljs-keyword">if</span> (targetIndex !== -<span class="hljs-number">1</span>) {
<span class="hljs-keyword">const</span> checkpointsToRemove = <span class="hljs-variable language_">this</span>.<span class="hljs-property">rollbackStack</span>.<span class="hljs-title function_">splice</span>(targetIndex + <span class="hljs-number">1</span>);
checkpointsToRemove.<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">id</span> =></span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">stateStorage</span>.<span class="hljs-title function_">delete</span>(id));
removedCount = checkpointsToRemove.<span class="hljs-property">length</span>;
}
<span class="hljs-keyword">const</span> rollbackDuration = <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>() - rollbackStart;
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`Rollback completed: <span class="hljs-subst">${checkpoint.id}</span>`</span>, {
<span class="hljs-attr">rollbackTime</span>: rollbackDuration,
<span class="hljs-attr">restoredDataSize</span>: <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(restoredData).<span class="hljs-property">length</span>,
<span class="hljs-attr">checkpointsRemoved</span>: removedCount,
<span class="hljs-attr">originalTimestamp</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(checkpoint.<span class="hljs-property">timestamp</span>).<span class="hljs-title function_">toLocaleString</span>()
});
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>,
<span class="hljs-attr">data</span>: restoredData,
<span class="hljs-attr">metadata</span>: checkpoint.<span class="hljs-property">metadata</span>,
rollbackDuration
};
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">error</span>(<span class="hljs-string">`Rollback failed for checkpoint <span class="hljs-subst">${checkpoint.id}</span>:`</span>, error);
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(<span class="hljs-string">`Rollback operation failed: <span class="hljs-subst">${error.message}</span>`</span>);
}
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">createTransactionalScope</span>(<span class="hljs-params">scopeName, operation</span>) {
<span class="hljs-keyword">const</span> transactionId = <span class="hljs-string">`<span class="hljs-subst">${scopeName}</span>_<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>`</span>;
<span class="hljs-keyword">const</span> initialState = <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">captureCurrentState</span>();
<span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">saveCheckpoint</span>(<span class="hljs-string">`pre_<span class="hljs-subst">${transactionId}</span>`</span>, initialState, {
<span class="hljs-attr">transactionScope</span>: scopeName,
<span class="hljs-attr">type</span>: <span class="hljs-string">'transaction_start'</span>
});
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-title function_">operation</span>();
<span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">saveCheckpoint</span>(<span class="hljs-string">`post_<span class="hljs-subst">${transactionId}</span>`</span>, result, {
<span class="hljs-attr">transactionScope</span>: scopeName,
<span class="hljs-attr">type</span>: <span class="hljs-string">'transaction_complete'</span>
});
<span class="hljs-keyword">return</span> result;
} <span class="hljs-keyword">catch</span> (error) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">warn</span>(<span class="hljs-string">`Transaction <span class="hljs-subst">${scopeName}</span> failed, initiating rollback`</span>, {
<span class="hljs-attr">error</span>: error.<span class="hljs-property">message</span>,
transactionId
});
<span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">rollbackToCheckpoint</span>(<span class="hljs-string">`pre_<span class="hljs-subst">${transactionId}</span>`</span>, {
<span class="hljs-attr">cleanupOperations</span>: <span class="hljs-keyword">await</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">getTransactionCleanup</span>(scopeName)
});
<span class="hljs-keyword">throw</span> error;
}
}
<span class="hljs-title function_">deepClone</span>(<span class="hljs-params">obj</span>) {
<span class="hljs-keyword">if</span> (obj === <span class="hljs-literal">null</span> || <span class="hljs-keyword">typeof</span> obj !== <span class="hljs-string">'object'</span>) <span class="hljs-keyword">return</span> obj;
<span class="hljs-keyword">if</span> (obj <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Date</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(obj.<span class="hljs-title function_">getTime</span>());
<span class="hljs-keyword">if</span> (obj <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Array</span>) <span class="hljs-keyword">return</span> obj.<span class="hljs-title function_">map</span>(<span class="hljs-function"><span class="hljs-params">item</span> =></span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">deepClone</span>(item));
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> obj === <span class="hljs-string">'object'</span>) {
<span class="hljs-keyword">const</span> cloned = {};
<span class="hljs-title class_">Object</span>.<span class="hljs-title function_">keys</span>(obj).<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">key</span> =></span> {
cloned[key] = <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">deepClone</span>(obj[key]);
});
<span class="hljs-keyword">return</span> cloned;
}
}
<span class="hljs-title function_">generateVersion</span>(<span class="hljs-params"></span>) {
<span class="hljs-keyword">return</span> <span class="hljs-string">`v<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>_<span class="hljs-subst">${<span class="hljs-built_in">Math</span>.random().toString(<span class="hljs-number">36</span>).substr(<span class="hljs-number">2</span>, <span class="hljs-number">9</span>)}</span>`</span>;
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">captureCurrentState</span>(<span class="hljs-params"></span>) {
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">timestamp</span>: <span class="hljs-title class_">Date</span>.<span class="hljs-title function_">now</span>()
};
}
<span class="hljs-keyword">async</span> <span class="hljs-title function_">executeCleanupOperations</span>(<span class="hljs-params">operations</span>) {
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> operation <span class="hljs-keyword">of</span> operations) {
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">await</span> <span class="hljs-title function_">operation</span>();
} <span class="hljs-keyword">catch</span> (cleanupError) {
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">warn</span>(<span class="hljs-string">'Cleanup operation failed:'</span>, cleanupError.<span class="hljs-property">message</span>);
}
}
}
<span class="hljs-title function_">getStateHistory</span>(<span class="hljs-params"></span>) {
<span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">rollbackStack</span>.<span class="hljs-title function_">map</span>(<span class="hljs-function"><span class="hljs-params">id</span> =></span> {
<span class="hljs-keyword">const</span> checkpoint = <span class="hljs-variable language_">this</span>.<span class="hljs-property">stateStorage</span>.<span class="hljs-title function_">get</span>(id);
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">id</span>: checkpoint.<span class="hljs-property">id</span>,
<span class="hljs-attr">timestamp</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(checkpoint.<span class="hljs-property">timestamp</span>).<span class="hljs-title function_">toLocaleString</span>(),
<span class="hljs-attr">size</span>: checkpoint.<span class="hljs-property">metadata</span>.<span class="hljs-property">size</span>,
<span class="hljs-attr">compressed</span>: checkpoint.<span class="hljs-property">compressed</span> || <span class="hljs-literal">false</span>,
<span class="hljs-attr">metadata</span>: checkpoint.<span class="hljs-property">metadata</span>
};
});
}
}
Plataformas como o Latenode facilitam a integração de mecanismos robustos de recuperação de erros em fluxos de trabalho de automação. Ao aplicar técnicas de preservação de estado e rollback, como mostrado acima, você pode criar processos resilientes baseados em JavaScript que mantêm a integridade dos dados, mesmo quando surgem problemas inesperados. Essa abordagem complementa as estratégias de tratamento de erros, garantindo que os fluxos de trabalho possam continuar sem interrupções.
Tabela de comparação
O JavaScript oferece diversas técnicas de recuperação de erros, cada uma adaptada a necessidades e cenários específicos. A escolha do método certo depende da compreensão de seus pontos fortes, limitações e como eles se alinham aos requisitos do seu fluxo de trabalho.
| Técnica | Eficácia da recuperação de erros | Complexidade de implementação | Mais adequado para | Impacto no desempenho | Curva de aprendizado |
|---|---|---|---|---|---|
| Tratamento de erros Try-Catch e Async | Alto para erros previsíveis | Baixa | Chamadas de API, operações de banco de dados, E/S de arquivo | Despesas mínimas | Amigável para iniciantes |
| Classes de erro personalizadas | Muito alto para erros categorizados | Suporte: | Fluxos de trabalho de várias etapas, aplicativos voltados para o usuário | Sobrecarga baixa | Nível intermediário |
| Relançamento de erros e enriquecimento de contexto | Alto para depuração de fluxos complexos | Médio-Alto | Chamadas de função aninhadas, microsserviços | Sobrecarga moderada | Intermediário-Avançado |
| Estratégias automatizadas de repetição e retirada | Excelente para falhas transitórias | Alta | Solicitações de rede, chamadas de serviço externo | Sobrecarga moderada | Avançado |
| Preservação e reversão do estado do fluxo de trabalho | Excelente para integridade de dados | Muito alto | Processos de longa duração, transações financeiras | Alto overhead | Avançado |
Cada uma dessas técnicas desempenha um papel específico na criação de fluxos de trabalho resilientes e confiáveis. Veja abaixo uma análise mais detalhada de como elas funcionam e quando usá-las.
Tratamento de erros Try-Catch e Async é a opção ideal para contenção rápida e direta de erros. É particularmente útil para lidar com erros previsíveis em tarefas como chamadas de API ou operações de arquivo, exigindo configuração mínima e oferecendo grande facilidade de uso.
Classes de erro personalizadas Destaque-se quando os fluxos de trabalho precisam diferenciar entre vários tipos de erros. Ao categorizar os erros, eles permitem estratégias de recuperação direcionadas, tornando-os ideais para aplicações complexas ou sistemas voltados para o usuário.
Relançamento de erros e enriquecimento de contexto é indispensável para depurar fluxos de trabalho complexos. Ao adicionar contexto aos erros à medida que se propagam, essa técnica ajuda a rastrear problemas até sua origem, o que é especialmente útil em chamadas de função aninhadas ou microsserviços.
Estratégias automatizadas de repetição e retirada Aborde problemas transitórios de forma eficaz, como timeouts de rede ou falhas de serviços externos. Configurar novas tentativas com intervalos de recuo garante estabilidade, mas uma configuração cuidadosa é crucial para evitar atrasos desnecessários.
Preservação e reversão do estado do fluxo de trabalho Garante a integridade dos dados em operações de alto risco. Ao gerenciar pontos de verificação e retornar a estados anteriores em caso de erros, é particularmente valioso para processos de longa duração ou transações financeiras que exigem precisão.
Ao projetar fluxos de trabalho de automação no Latenode, essas técnicas podem ser combinadas para máxima eficiência. Por exemplo, você pode usar try-catch para tratamento básico de erros, integrar classes de erro personalizadas para falhas específicas do fluxo de trabalho e aplicar preservação de estado para operações críticas. Essa abordagem em camadas garante uma recuperação robusta de erros sem complicar tarefas mais simples.
Em última análise, a chave para uma gestão de erros eficaz reside em adequar a complexidade da sua estratégia de recuperação às necessidades do seu fluxo de trabalho. Por exemplo, uma transformação de dados simples pode exigir apenas o tratamento try-catch, enquanto uma integração em várias etapas envolvendo dados sensíveis exige uma abordagem mais abrangente. Ao adaptar essas técnicas ao seu cenário específico, você pode alcançar confiabilidade e eficiência.
Conclusão
Uma estratégia de defesa em camadas é essencial para garantir a confiabilidade em fluxos de trabalho de automação, especialmente ao lidar com a recuperação de erros em automação baseada em JavaScript. A combinação de múltiplas técnicas cria uma estrutura robusta para lidar com erros de forma eficaz. blocos try-catch para contenção imediata de erros classes de erro personalizadas que adicionam contexto de depuração valioso, cada método desempenha um papel crítico. Erro ao relançar preserva rastreamentos de pilha para melhor análise, estratégias de repetição automatizadas abordar falhas transitórias e preservação do estado protege a integridade dos dados durante operações complexas. Uma pesquisa de 2024 com engenheiros de automação revelou que 68% consideram o tratamento robusto de erros como o fator mais crítico na confiabilidade do fluxo de trabalho .
Em aplicações práticas, esses métodos funcionam perfeitamente em conjunto. Por exemplo, blocos try-catch podem lidar com falhas de API em tempo real, enquanto classes de erro personalizadas diferenciam entre os tipos de erro. Erros relançados, enriquecidos com contexto adicional, aprimoram o registro e a depuração. Mecanismos de nova tentativa com backoff exponencial gerenciam problemas temporários com eficácia, e a preservação do estado garante que os fluxos de trabalho possam se recuperar sem problemas e sem perda de dados. Dados do setor sugerem que o tratamento estruturado de erros pode reduzir o tempo de inatividade não planejado em fluxos de trabalho em até 40% .
Plataformas que suportam fluxos de trabalho visuais e baseados em código são essenciais para implementar essas estratégias com eficiência. Nó latente Destaca-se como uma ferramenta poderosa para incorporar padrões de recuperação de erros. Seu design de fluxo de trabalho visual, combinado com suporte nativo a JavaScript, facilita a integração da lógica de tratamento de erros pelos desenvolvedores. O banco de dados integrado da plataforma facilita a preservação do estado, enquanto suas ferramentas de orquestração e registro simplificam o monitoramento e a recuperação. Com as amplas integrações do Latenode, você pode implementar mecanismos de repetição em vários serviços externos, mantendo o gerenciamento de erros centralizado.
O sucesso das estratégias de recuperação de erros depende da adaptação da complexidade delas às necessidades específicas do seu fluxo de trabalho. Para tarefas mais simples, como transformações de dados, blocos try-catch podem ser suficientes. No entanto, processos mais complexos, como integrações em várias etapas envolvendo dados sensíveis, exigem uma abordagem abrangente que incorpore todas as cinco técnicas. Ao utilizar plataformas com design de fluxo de trabalho visual e baseado em código, você pode construir sistemas de automação resilientes que não apenas lidam com erros com elegância, mas também se adaptam e escalam conforme suas necessidades evoluem.
Perguntas
Quais são os benefícios de usar classes de erro personalizadas em fluxos de trabalho JavaScript?
Classes de erro personalizadas em JavaScript oferecem uma maneira de lidar com erros de forma mais eficaz, permitindo definir tipos de erro específicos, adaptados a diferentes cenários. Esse método melhora a clareza e a estrutura no gerenciamento de erros, facilitando a identificação da origem de um problema. Usando ferramentas como instanceof, você pode determinar com precisão o tipo de erro encontrado.
Ao incorporar classes de erro personalizadas, a depuração se torna mais simples, a legibilidade do código melhora e os fluxos de trabalho se tornam mais fáceis de gerenciar. Essa abordagem garante que os erros sejam tratados de forma consistente, o que é especialmente valioso na manutenção de sistemas complexos ou processos de automação.
Quais são as vantagens de usar estratégias de nova tentativa e recuo para recuperação de erros em fluxos de trabalho JavaScript?
Estratégias de repetição e recuo desempenham um papel fundamental para garantir que os fluxos de trabalho JavaScript permaneçam confiáveis e robustos. Esses métodos permitem que os sistemas se recuperem automaticamente de erros temporários, reduzindo o tempo de inatividade e limitando a necessidade de solução de problemas manuais.
Uma técnica amplamente utilizada, recuo exponencial, espaça as tentativas de repetição aumentando progressivamente o atraso entre cada uma. Essa abordagem ajuda a evitar a sobrecarga do sistema, alivia o congestionamento da rede e otimiza o uso de recursos. Ao implementar essas estratégias, os sistemas podem gerenciar falhas transitórias com mais eficácia, aprimorando o desempenho e a experiência geral do usuário.
Como a preservação de estados de fluxo de trabalho e o uso de reversões melhoram a confiabilidade da automação?
Preservar os estados do fluxo de trabalho e implementar reversões desempenham um papel crucial para garantir a confiabilidade dos processos de automação. Essas estratégias permitem que os sistemas retornem a um estado estável anterior quando ocorrem erros, minimizando interrupções e evitando que atualizações incorretas afetem as operações em andamento. Essa abordagem garante uma recuperação mais tranquila e mantém os processos funcionando com eficiência.
Mecanismos de reversão automatizados são particularmente valiosos, pois reduzem a necessidade de intervenção manual, mantêm a continuidade operacional e fortalecem a resiliência do sistema. Ao proteger fluxos de trabalho essenciais, essas práticas ajudam a construir soluções de automação robustas e confiáveis.
Posts Relacionados do Blog
- Depurando scripts do Puppeteer: do modo slowMo às técnicas avançadas
- Projetando fluxos de trabalho JavaScript resilientes a erros
- JavaScript personalizado em ferramentas de fluxo de trabalho visual
- Tratamento de erros em fluxos de trabalho de baixo código: práticas recomendadas



