fix: remove cache do configService; remove cacheService.js (nao usado)
- configService agora le direto do banco (sem TTL, sem stale data) - invalidarConfig virou no-op (não há cache para invalidar) - cacheService.js removido (so era usado pelo configService) - endpoint /metrics sem referencia ao cacheService
This commit is contained in:
@@ -137,23 +137,6 @@ const MIGRACOES = [
|
|||||||
'ALTER TABLE CHATC2_CONVERSAS ADD CON_RESOLUCAO VARCHAR(4000)',
|
'ALTER TABLE CHATC2_CONVERSAS ADD CON_RESOLUCAO VARCHAR(4000)',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
// MIGRAÇÃO 25: Generator para MENSAGEM_CLIENTES (tabela do ERP)
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
{
|
|
||||||
id: 25,
|
|
||||||
descricao: 'Criar generator para MENSAGEM_CLIENTES (tabela ja existe no ERP)',
|
|
||||||
sql: [
|
|
||||||
'CREATE GENERATOR GEN_MENSAGEM_CLIENTES',
|
|
||||||
],
|
|
||||||
async after(alias) {
|
|
||||||
try {
|
|
||||||
const r = await db.query(alias, 'SELECT COALESCE(MAX(MSC_CODIGO_ID),0)+1 AS V FROM MENSAGEM_CLIENTES');
|
|
||||||
await db.execute(alias, 'SET GENERATOR GEN_MENSAGEM_CLIENTES TO ' + (r[0]?.V || 1));
|
|
||||||
} catch (_) {}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|||||||
@@ -736,7 +736,7 @@ class ChatController {
|
|||||||
// Salva resolução na tabela MENSAGENS_CLIENTES como aviso (se configurado)
|
// Salva resolução na tabela MENSAGENS_CLIENTES como aviso (se configurado)
|
||||||
if (isS(fl.CFE_RESOLUCAO_SALVAR_MSC) && resolucao && c.CON_CLIENTE_ID) {
|
if (isS(fl.CFE_RESOLUCAO_SALVAR_MSC) && resolucao && c.CON_CLIENTE_ID) {
|
||||||
try {
|
try {
|
||||||
const mscId = await db.nextId(alias, 'GEN_MENSAGEM_CLIENTES');
|
const mscId = await db.nextId(alias, 'GEN_MENSAGEM_CLIENTES_ID');
|
||||||
await db.execute(alias,
|
await db.execute(alias,
|
||||||
`INSERT INTO MENSAGEM_CLIENTES (MSC_CODIGO_ID, MSC_CLIENTE_ID, MSC_USUARIO_ID, MSC_DT_MENSAGEM, MSC_AVISO, MSC_MENSAGEM)
|
`INSERT INTO MENSAGEM_CLIENTES (MSC_CODIGO_ID, MSC_CLIENTE_ID, MSC_USUARIO_ID, MSC_DT_MENSAGEM, MSC_AVISO, MSC_MENSAGEM)
|
||||||
VALUES (?, ?, ?, CURRENT_TIMESTAMP, 'S', ?)`,
|
VALUES (?, ?, ?, CURRENT_TIMESTAMP, 'S', ?)`,
|
||||||
|
|||||||
+1
-1
@@ -98,7 +98,7 @@ const GENERATORS = [
|
|||||||
'GEN_CHATC2_CSAT_AVALIACOES',
|
'GEN_CHATC2_CSAT_AVALIACOES',
|
||||||
'GEN_CHATC2_MOTIVOS_ATENDIMENTO',
|
'GEN_CHATC2_MOTIVOS_ATENDIMENTO',
|
||||||
'GEN_CHATC2_AGENDAMENTOS',
|
'GEN_CHATC2_AGENDAMENTOS',
|
||||||
'GEN_MENSAGEM_CLIENTES',
|
'GEN_MENSAGEM_CLIENTES_ID',
|
||||||
];
|
];
|
||||||
|
|
||||||
async function nextId(alias, generatorName) {
|
async function nextId(alias, generatorName) {
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ router.get('/api/:alias/metrics', authenticateToken, (req, res) => {
|
|||||||
uptimeSeconds: Math.floor(process.uptime()),
|
uptimeSeconds: Math.floor(process.uptime()),
|
||||||
memory: process.memoryUsage(),
|
memory: process.memoryUsage(),
|
||||||
metrics: metrics.getAll(),
|
metrics: metrics.getAll(),
|
||||||
cache: require('../services/cacheService').stats(),
|
|
||||||
pool: require('../database').poolStats(),
|
pool: require('../database').poolStats(),
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
/**
|
|
||||||
* Cache em memória com TTL.
|
|
||||||
*
|
|
||||||
* Simples, sem dependências externas. Usado para evitar consultas repetidas
|
|
||||||
* ao banco para dados que mudam raramente (ex: configurações da empresa).
|
|
||||||
*
|
|
||||||
* Uso:
|
|
||||||
* const cache = require('../services/cacheService');
|
|
||||||
* let valor = cache.get('chave');
|
|
||||||
* if (!valor) {
|
|
||||||
* valor = await db.query(...);
|
|
||||||
* cache.set('chave', valor, 60000); // TTL 60s
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
const store = new Map();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Armazena um valor no cache.
|
|
||||||
* @param {string} key
|
|
||||||
* @param {*} value
|
|
||||||
* @param {number} [ttlMs=60000] - Tempo de vida em ms (padrão: 1 minuto)
|
|
||||||
*/
|
|
||||||
function set(key, value, ttlMs = 60000) {
|
|
||||||
store.set(key, {
|
|
||||||
value,
|
|
||||||
expiresAt: Date.now() + ttlMs,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recupera um valor do cache. Retorna undefined se expirado ou inexistente.
|
|
||||||
* @param {string} key
|
|
||||||
* @returns {*|undefined}
|
|
||||||
*/
|
|
||||||
function get(key) {
|
|
||||||
const entry = store.get(key);
|
|
||||||
if (!entry) return undefined;
|
|
||||||
if (Date.now() > entry.expiresAt) {
|
|
||||||
store.delete(key);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return entry.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalida uma chave específica.
|
|
||||||
* @param {string} key
|
|
||||||
*/
|
|
||||||
function del(key) {
|
|
||||||
store.delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invalida todas as chaves que começam com o prefixo.
|
|
||||||
* Útil para invalidar todo o cache de uma empresa (ex: 'config:5:').
|
|
||||||
* @param {string} prefix
|
|
||||||
*/
|
|
||||||
function delByPrefix(prefix) {
|
|
||||||
for (const key of store.keys()) {
|
|
||||||
if (key.startsWith(prefix)) {
|
|
||||||
store.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retorna estatísticas do cache para debug.
|
|
||||||
*/
|
|
||||||
function stats() {
|
|
||||||
let total = 0, valid = 0;
|
|
||||||
const now = Date.now();
|
|
||||||
for (const [, entry] of store) {
|
|
||||||
total++;
|
|
||||||
if (entry.expiresAt > now) valid++;
|
|
||||||
}
|
|
||||||
return { total, valid, expired: total - valid };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limpeza periódica de entradas expiradas (evita vazamento de memória)
|
|
||||||
const intervalo = setInterval(() => {
|
|
||||||
const now = Date.now();
|
|
||||||
for (const [key, entry] of store) {
|
|
||||||
if (entry.expiresAt <= now) store.delete(key);
|
|
||||||
}
|
|
||||||
}, 60000);
|
|
||||||
if (intervalo.unref) intervalo.unref();
|
|
||||||
|
|
||||||
module.exports = { set, get, del, delByPrefix, stats };
|
|
||||||
@@ -1,56 +1,31 @@
|
|||||||
/**
|
/**
|
||||||
* Serviço de configuração da empresa com cache.
|
* Serviço de configuração da empresa (sem cache).
|
||||||
*
|
*
|
||||||
* As flags CFE_* (triagem, saudação, CSAT, etc.) são lidas em toda operação
|
* Lê direto do banco — sem TTL, sem stale data.
|
||||||
* de chat/triagem/webhook. Este serviço armazena em cache (TTL 2min) e
|
* As flags CFE_* são consultadas a cada operação, então refletem
|
||||||
* invalida automaticamente quando as configurações são alteradas.
|
* imediatamente qualquer alteração salva em Settings.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const db = require('../database');
|
const db = require('../database');
|
||||||
const cache = require('./cacheService');
|
|
||||||
|
|
||||||
const TTL = 2 * 60 * 1000; // 2 minutos
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retorna a configuração completa de uma empresa (cacheada).
|
* Retorna a configuração completa de uma empresa (direto do banco).
|
||||||
* Invalidação: chamar invalidarConfig(alias, empresaId) após salvar settings.
|
|
||||||
*
|
*
|
||||||
* @param {string} alias
|
* @param {string} alias
|
||||||
* @param {number} empresaId
|
* @param {number} empresaId
|
||||||
* @returns {Promise<object>} Linha da tabela CHATC2_CONFIGURACOES_EMPRESA
|
* @returns {Promise<object>}
|
||||||
*/
|
*/
|
||||||
async function getConfig(alias, empresaId) {
|
async function getConfig(alias, empresaId) {
|
||||||
const key = 'cfg:' + alias + ':' + empresaId;
|
|
||||||
const cached = cache.get(key);
|
|
||||||
if (cached) return cached;
|
|
||||||
|
|
||||||
// Garante que o registro existe (insere se não existir)
|
|
||||||
await garantirRegistro(alias, empresaId);
|
await garantirRegistro(alias, empresaId);
|
||||||
|
|
||||||
const result = await db.query(alias,
|
const result = await db.query(alias,
|
||||||
'SELECT * FROM CHATC2_CONFIGURACOES_EMPRESA WHERE CFE_EMPRESA_ID = ?',
|
'SELECT * FROM CHATC2_CONFIGURACOES_EMPRESA WHERE CFE_EMPRESA_ID = ?',
|
||||||
[empresaId]);
|
[empresaId]);
|
||||||
|
return result[0] || {};
|
||||||
const config = result[0] || {};
|
|
||||||
cache.set(key, config, TTL);
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** No-op: não há cache para invalidar */
|
||||||
* Invalida o cache de configuração de uma empresa.
|
function invalidarConfig() {}
|
||||||
* Deve ser chamado após salvar alterações nas configurações.
|
|
||||||
*
|
|
||||||
* @param {string} alias
|
|
||||||
* @param {number} empresaId
|
|
||||||
*/
|
|
||||||
function invalidarConfig(alias, empresaId) {
|
|
||||||
cache.del('cfg:' + alias + ':' + empresaId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Garante que existe um registro de configuração para a empresa.
|
|
||||||
* Idempotente — se já existe, não faz nada.
|
|
||||||
*/
|
|
||||||
async function garantirRegistro(alias, empresaId) {
|
async function garantirRegistro(alias, empresaId) {
|
||||||
try {
|
try {
|
||||||
const existe = await db.query(alias,
|
const existe = await db.query(alias,
|
||||||
@@ -63,7 +38,6 @@ async function garantirRegistro(alias, empresaId) {
|
|||||||
`, [empresaId]);
|
`, [empresaId]);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Tabela pode não existir ainda — ignora
|
|
||||||
if (!e.message.includes('unknown') && !e.message.includes('não encontrado')) {
|
if (!e.message.includes('unknown') && !e.message.includes('não encontrado')) {
|
||||||
console.error('[ConfigService] Erro ao garantir registro:', e.message.substring(0, 100));
|
console.error('[ConfigService] Erro ao garantir registro:', e.message.substring(0, 100));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user