ajustes no main_async
This commit is contained in:
parent
c5e5785718
commit
d7f1689610
|
|
@ -1,7 +1,12 @@
|
||||||
import sys
|
import sys
|
||||||
import io
|
import io
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
|
import signal
|
||||||
|
import traceback
|
||||||
|
import multiprocessing
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
|
|
||||||
from manager_worker.main import main as iniciar_manager_worker
|
from manager_worker.main import main as iniciar_manager_worker
|
||||||
from health_worker.main import main as iniciar_health_worker
|
from health_worker.main import main as iniciar_health_worker
|
||||||
from visual_worker.main import main as iniciar_visual_worker
|
from visual_worker.main import main as iniciar_visual_worker
|
||||||
|
|
@ -9,12 +14,41 @@ from camera_worker.main import main as iniciar_camera_worker
|
||||||
from weed_worker.main import main as iniciar_weed_worker
|
from weed_worker.main import main as iniciar_weed_worker
|
||||||
from shared.contexto_global_redis import ContextoGlobalRedis
|
from shared.contexto_global_redis import ContextoGlobalRedis
|
||||||
|
|
||||||
#sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
||||||
|
|
||||||
def main():
|
SHUTDOWN = False
|
||||||
ContextoGlobalRedis.reset_operacao()
|
|
||||||
|
|
||||||
processos = [
|
|
||||||
|
def configurar_console():
|
||||||
|
"""
|
||||||
|
Garante saída UTF-8 quando o processo é iniciado pelo C# com stdout/stderr redirecionados.
|
||||||
|
Evita problemas com emojis/logs em Windows.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if hasattr(sys.stdout, "reconfigure"):
|
||||||
|
sys.stdout.reconfigure(encoding="utf-8", errors="replace", line_buffering=True)
|
||||||
|
|
||||||
|
if hasattr(sys.stderr, "reconfigure"):
|
||||||
|
sys.stderr.reconfigure(encoding="utf-8", errors="replace", line_buffering=True)
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace", line_buffering=True)
|
||||||
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace", line_buffering=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
print(msg, flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
def tratar_sinal(sig, frame):
|
||||||
|
global SHUTDOWN
|
||||||
|
SHUTDOWN = True
|
||||||
|
log(f"⛔ Sinal recebido: {sig}. Encerrando núcleo de workers...")
|
||||||
|
|
||||||
|
|
||||||
|
def criar_processos():
|
||||||
|
return [
|
||||||
Process(target=iniciar_manager_worker, name="ManagerWorker"),
|
Process(target=iniciar_manager_worker, name="ManagerWorker"),
|
||||||
Process(target=iniciar_health_worker, name="HealthWorker"),
|
Process(target=iniciar_health_worker, name="HealthWorker"),
|
||||||
Process(target=iniciar_visual_worker, name="VisualWorker"),
|
Process(target=iniciar_visual_worker, name="VisualWorker"),
|
||||||
|
|
@ -22,20 +56,118 @@ def main():
|
||||||
Process(target=iniciar_weed_worker, name="WeedWorker"),
|
Process(target=iniciar_weed_worker, name="WeedWorker"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def iniciar_processos(processos):
|
||||||
for p in processos:
|
for p in processos:
|
||||||
p.daemon = True
|
# Não usar daemon em campo.
|
||||||
|
# Se algum worker precisar criar subprocessos, daemon=True pode quebrar.
|
||||||
|
p.daemon = False
|
||||||
p.start()
|
p.start()
|
||||||
print(f"✅ Processo '{p.name}' iniciado com PID {p.pid}")
|
log(f"✅ Processo '{p.name}' iniciado com PID {p.pid}")
|
||||||
|
|
||||||
|
|
||||||
|
def encerrar_processos(processos, motivo="encerramento solicitado"):
|
||||||
|
log(f"⛔ Encerrando processos filhos: {motivo}")
|
||||||
|
|
||||||
|
for p in processos:
|
||||||
|
try:
|
||||||
|
if p.is_alive():
|
||||||
|
log(f"⛔ Terminando '{p.name}' PID={p.pid}")
|
||||||
|
p.terminate()
|
||||||
|
except Exception as ex:
|
||||||
|
log(f"⚠️ Erro ao terminar '{p.name}': {ex}")
|
||||||
|
|
||||||
|
limite_s = 8
|
||||||
|
inicio = time.time()
|
||||||
|
|
||||||
|
while time.time() - inicio < limite_s:
|
||||||
|
vivos = [p for p in processos if p.is_alive()]
|
||||||
|
if not vivos:
|
||||||
|
break
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
for p in processos:
|
||||||
|
try:
|
||||||
|
if p.is_alive():
|
||||||
|
log(f"🧨 Matando processo resistente '{p.name}' PID={p.pid}")
|
||||||
|
p.kill()
|
||||||
|
except Exception as ex:
|
||||||
|
log(f"⚠️ Erro ao matar '{p.name}': {ex}")
|
||||||
|
|
||||||
|
for p in processos:
|
||||||
|
try:
|
||||||
|
p.join(timeout=2)
|
||||||
|
log(f"✅ Processo '{p.name}' encerrado. ExitCode={p.exitcode}")
|
||||||
|
except Exception as ex:
|
||||||
|
log(f"⚠️ Erro ao aguardar '{p.name}': {ex}")
|
||||||
|
|
||||||
|
|
||||||
|
def monitorar_processos(processos):
|
||||||
|
"""
|
||||||
|
Mantém o processo pai vivo e supervisiona os filhos.
|
||||||
|
Se algum worker morrer sozinho, finaliza todos e sai com erro.
|
||||||
|
O C# deve reiniciar o núcleo.
|
||||||
|
"""
|
||||||
|
ultimo_status = 0
|
||||||
|
|
||||||
|
while not SHUTDOWN:
|
||||||
|
mortos = [p for p in processos if p.exitcode is not None]
|
||||||
|
|
||||||
|
if mortos:
|
||||||
|
for p in mortos:
|
||||||
|
log(f"❌ Worker morreu: {p.name}, PID={p.pid}, ExitCode={p.exitcode}")
|
||||||
|
|
||||||
|
encerrar_processos(processos, motivo="worker morreu")
|
||||||
|
return 2
|
||||||
|
|
||||||
|
agora = time.time()
|
||||||
|
if agora - ultimo_status >= 10:
|
||||||
|
status = ", ".join([f"{p.name}=PID:{p.pid}/alive:{p.is_alive()}" for p in processos])
|
||||||
|
log(f"💓 Supervisor ativo. {status}")
|
||||||
|
ultimo_status = agora
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
encerrar_processos(processos, motivo="shutdown solicitado")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
configurar_console()
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, tratar_sinal)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
signal.signal(signal.SIGTERM, tratar_sinal)
|
||||||
time.sleep(1)
|
except Exception:
|
||||||
except KeyboardInterrupt:
|
pass
|
||||||
print("⛔ Encerrando processos...")
|
|
||||||
for p in processos:
|
log("🚀 Iniciando supervisor dos workers Python...")
|
||||||
p.terminate()
|
log(f"Python exe: {sys.executable}")
|
||||||
p.join()
|
log(f"CWD: {os.getcwd()}")
|
||||||
print("✅ Todos os processos encerrados.")
|
log(f"Args: {sys.argv}")
|
||||||
|
|
||||||
|
ContextoGlobalRedis.reset_operacao()
|
||||||
|
|
||||||
|
processos = criar_processos()
|
||||||
|
iniciar_processos(processos)
|
||||||
|
|
||||||
|
exit_code = monitorar_processos(processos)
|
||||||
|
|
||||||
|
log(f"✅ Supervisor finalizado. ExitCode={exit_code}")
|
||||||
|
return exit_code
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
multiprocessing.freeze_support()
|
||||||
|
|
||||||
|
try:
|
||||||
|
codigo = main()
|
||||||
|
sys.exit(codigo)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
log("⛔ KeyboardInterrupt no processo pai.")
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception:
|
||||||
|
log("💥 ERRO FATAL NO PROCESSO PAI main_async.py")
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(1)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue