adicionado modulo can no health worker

This commit is contained in:
Diego Freitas 2025-12-08 14:39:22 -03:00
parent 7f7ea84bd2
commit cdbcb8f1d7
1 changed files with 118 additions and 0 deletions

View File

@ -0,0 +1,118 @@
import time
from shared.contexto_global_redis import ContextoGlobalRedis
from shared.enums import StatusModulo, T_Code
from health_worker.modulos.base import ModuloDiagnosticoBase
class ModuloCAN(ModuloDiagnosticoBase):
def __init__(self):
self.t_code = T_Code.Can
self.nome = "CAN"
self.timeout = 5
def atualizar_saude(self):
try:
now = time.perf_counter()
m = ContextoGlobalRedis.get_modulo(self.t_code) or {}
SAUDE_MIN_ALERTA = 80
PESO_POR_ERRO = 10 # cada erro pode pesar até 10%
PESO_MAX_ERROS = 40 # máximo 40% de penalização vinda só de erros críticos
JANELA_RESET_EC = 600.0 # 10 minutos
conectado = bool(m.get("conectado", False))
inicado = bool(m.get("iniciado", False))
executando = bool(m.get("executando", False))
erros_criticos = int(m.get("erros_criticos", 0))
# períodos-alvo (segundos) — se vier 0/None, usa fallback prudente
tb_tx = float(m.get("tempo_base_tx", 1.0)) or 1.0
tb_rx = float(m.get("tempo_base_rx", 1.0)) or 1.0
# timestamps monotônicos (segundos)
last_tx = float(m.get("last_tx", 0.0))
last_rx = float(m.get("last_rx", 0.0))
last_ec = float(m.get("last_ec", 0.0))
age_tx = max(0.0, now - last_tx)
age_rx = max(0.0, now - last_rx)
age_ec = max(0.0, now - last_ec)
# tempo-limite pra considerar "morto": 3 períodos ou 3s (o que for maior)
timeout_rx = max(30.0, 3.0 * tb_rx)
timeout_tx = max(30.0, 3.0 * tb_tx) # informativo (RX é vital)
saude = 100
motivos = []
if not conectado:
saude = 0
motivos.append("desconectado")
else:
if not inicado:
saude -= 50
motivos.append("não iniciado")
if executando:
# Penalização por atraso relativo ao período-alvo
# Ex.: se tb_rx=1s e age_rx=1.5s → atraso_rel=0.5 → penaliza 0.5*70=35%
atraso_rel_rx = max(0.0, (age_rx / tb_rx) - 1.0)
atraso_rel_tx = max(0.0, (age_tx / tb_tx) - 1.0)
p_rx = int(min(round(atraso_rel_rx * 60), 60)) # RX pesa mais (até 70%)
p_tx = int(min(round(atraso_rel_tx * 40), 40)) # TX pesa menos (até 40%)
if p_rx > 0:
saude -= p_rx
motivos.append(f"RX atrasado {age_rx:.2f}s (-{p_rx}%)")
if p_tx > 0:
saude -= p_tx
motivos.append(f"TX atrasado {age_tx:.2f}s (-{p_tx}%)")
if erros_criticos > 0 and age_ec <= JANELA_RESET_EC:
# penalidade base cresce com o número de erros, limitada pelo teto
penalidade_base = min(erros_criticos * PESO_POR_ERRO, PESO_MAX_ERROS)
# fator de recência: 1 se acabou de acontecer, 0 se está no limite da janela
fator_recencia = max(0.0, 1.0 - (age_ec / JANELA_RESET_EC))
p_ec = int(round(penalidade_base * fator_recencia))
if p_ec > 0:
saude -= p_ec
motivos.append(f"{erros_criticos} erros críticos, último há {age_ec:.0f}s (-{p_ec}%)")
saude = max(saude, 0)
status = StatusModulo.OPERANTE
if not conectado:
status = StatusModulo.DESCONECTADO
elif saude <= 0:
status = StatusModulo.FALHA
elif saude < SAUDE_MIN_ALERTA:
status = StatusModulo.ALERTA
payload = {
"conectado": conectado,
"status": status.value,
"saude": saude,
"motivos": motivos,
"saude_individual": [],
"condicoes_operacionais": [],
"detalhes": {
"age_rx_s": age_rx,
"age_tx_s": age_tx,
"age_ec_s": age_ec,
"timeout_rx_s": timeout_rx,
"timeout_tx_s": timeout_tx,
"periodo_alvo_rx_s": tb_rx,
"periodo_alvo_tx_s": tb_tx,
},
}
ContextoGlobalRedis.atualizar_ctx_dict(
ContextoGlobalRedis.ModKey(self.t_code),
saude=payload
)
except Exception as e:
print(f"Erro ao atualizar saude do modulo {self.t_code.name}: {e}")