snglpi/src/controllers/processErrorController.js

60 lines
2.6 KiB
JavaScript
Raw Normal View History

const TicketSyncModel = require('../models/ticketSyncModel');
const { logInfo, logError, logWarning } = require('../utils/logger');
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
const MAX_ERROR_RETRIES = Number(process.env.MAX_ERROR_RETRIES || 5);
const processErrorController = async () => {
logInfo('Iniciando verificação de tickets com erro...');
try {
const errorTickets = await TicketSyncModel.getTicketsInErrorState();
if (errorTickets.length === 0) {
logInfo('Nenhum ticket com erro encontrado para reprocessamento.');
return;
}
logWarning(`Encontrados ${errorTickets.length} tickets com erro. Tentando reprocessar...`);
for (const ticket of errorTickets) {
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
const retryCount = await TicketSyncModel.bumpErrorRetryCount(ticket.sn_ticket_id);
if (retryCount > MAX_ERROR_RETRIES) {
await TicketSyncModel.markPermanentError(ticket.sn_ticket_id);
logWarning(`Ticket SN ID ${ticket.sn_ticket_id} excedeu ${MAX_ERROR_RETRIES} tentativas de reprocessamento. Marcado como 'error_permanent' (requer intervencao manual).`);
continue;
}
let newSnStatus = ticket.sn_sync_status;
let newGlpiStatus = ticket.glpi_sync_status;
if (ticket.glpi_sync_status === 'error') {
newGlpiStatus = 'pending_check';
}
if (ticket.sn_sync_status === 'error_sync') newSnStatus = 'synced';
if (ticket.glpi_sync_status === 'error_sync') newGlpiStatus = 'synced';
if (ticket.sn_sync_status === 'error_closing') newSnStatus = 'pending_close';
if (ticket.glpi_sync_status === 'error_closing') newGlpiStatus = 'pending_close';
await TicketSyncModel.updateStatus(ticket.sn_ticket_id, newGlpiStatus, newSnStatus);
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
logInfo(`Ticket SN ID ${ticket.sn_ticket_id} resetado para reprocessamento (SN: ${newSnStatus}, GLPI: ${newGlpiStatus}, tentativa ${retryCount}/${MAX_ERROR_RETRIES}).`);
}
} catch (error) {
logError(error, 'Erro ao processar tickets com falha.');
}
};
module.exports = {
processErrorController
};
/**
* @file processErrorController.js
* @description Este controlador é responsável por gerenciar tickets que entraram em estado de erro durante o processo de sincronização.
* Ele busca todos os tickets marcados com status de erro (ex: 'error', 'error_sync') e os reseta para um estado anterior válido
* (ex: 'pending_check', 'synced'). Isso permite que os tickets sejam automaticamente reprocessados na próxima execução do ciclo de sincronização,
* aumentando a resiliência do sistema.
*/