Commit inicial con archivos existentes
This commit is contained in:
187
src/TranslationWorkerPool.php
Executable file
187
src/TranslationWorkerPool.php
Executable file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
class TranslationWorkerPool {
|
||||
private $workers = [];
|
||||
private $maxWorkers = 4;
|
||||
private $pdo;
|
||||
private $environment;
|
||||
private $running = true;
|
||||
|
||||
public function __construct($pdo, $maxWorkers = null) {
|
||||
$this->pdo = $pdo;
|
||||
|
||||
// Configurar número de workers desde environment
|
||||
if ($maxWorkers !== null) {
|
||||
$this->maxWorkers = $maxWorkers;
|
||||
} elseif (isset($_ENV['TRANSLATION_WORKERS'])) {
|
||||
$this->maxWorkers = (int)$_ENV['TRANSLATION_WORKERS'];
|
||||
}
|
||||
|
||||
// Capturar el environment del proceso padre
|
||||
$this->environment = getenv('APP_ENVIRONMENT') ?: 'pruebas';
|
||||
|
||||
custom_log("[WORKER_POOL] Inicializando con {$this->maxWorkers} workers");
|
||||
custom_log("[WORKER_POOL] Environment: {$this->environment}");
|
||||
}
|
||||
|
||||
public function start() {
|
||||
// Configurar manejadores de señales para el pool
|
||||
pcntl_async_signals(true);
|
||||
pcntl_signal(SIGINT, [$this, 'handleShutdown']);
|
||||
pcntl_signal(SIGTERM, [$this, 'handleShutdown']);
|
||||
|
||||
custom_log("[WORKER_POOL] Iniciando {$this->maxWorkers} workers...");
|
||||
|
||||
// Iniciar workers
|
||||
for ($i = 0; $i < $this->maxWorkers; $i++) {
|
||||
$this->spawnWorker($i);
|
||||
}
|
||||
|
||||
custom_log("[WORKER_POOL] Todos los workers iniciados");
|
||||
|
||||
// Supervisar workers
|
||||
$this->supervise();
|
||||
}
|
||||
|
||||
private function spawnWorker($id) {
|
||||
$pid = pcntl_fork();
|
||||
|
||||
if ($pid == -1) {
|
||||
// Error al hacer fork
|
||||
custom_log("[WORKER_POOL] ERROR: No se pudo crear worker {$id}");
|
||||
return false;
|
||||
} elseif ($pid == 0) {
|
||||
// Proceso hijo - ejecutar worker
|
||||
try {
|
||||
// Heredar environment del padre
|
||||
putenv('APP_ENVIRONMENT=' . $this->environment);
|
||||
|
||||
custom_log("[WORKER_{$id}] Iniciado con PID " . getmypid() . ", APP_ENVIRONMENT={$this->environment}");
|
||||
|
||||
// IMPORTANTE: Crear nueva conexión PDO para este worker
|
||||
// No usar la conexión del padre porque se cierra por inactividad
|
||||
$maxRetries = 3;
|
||||
$retryDelay = 2;
|
||||
$pdo = null;
|
||||
|
||||
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
|
||||
try {
|
||||
require_once __DIR__ . '/../includes/db.php';
|
||||
// $pdo se crea en db.php
|
||||
if (isset($pdo) && $pdo !== null) {
|
||||
custom_log("[WORKER_{$id}] Conexión a BD establecida");
|
||||
break;
|
||||
}
|
||||
} catch (Exception $dbError) {
|
||||
custom_log("[WORKER_{$id}] Intento {$attempt}/{$maxRetries} de conexión a BD falló: " . $dbError->getMessage());
|
||||
if ($attempt < $maxRetries) {
|
||||
sleep($retryDelay);
|
||||
} else {
|
||||
throw new Exception("No se pudo conectar a la BD después de {$maxRetries} intentos");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cargar dependencias necesarias
|
||||
require_once __DIR__ . '/Translate.php';
|
||||
require_once __DIR__ . '/TranslationWorker.php';
|
||||
|
||||
// Crear y ejecutar worker con su propia conexión
|
||||
$worker = new TranslationWorker($id, $pdo);
|
||||
$worker->run();
|
||||
|
||||
} catch (Exception $e) {
|
||||
custom_log("[WORKER_{$id}] ERROR FATAL: " . $e->getMessage());
|
||||
custom_log("[WORKER_{$id}] Stack trace: " . $e->getTraceAsString());
|
||||
}
|
||||
|
||||
exit(0);
|
||||
} else {
|
||||
// Proceso padre - registrar worker
|
||||
$this->workers[$id] = [
|
||||
'pid' => $pid,
|
||||
'started' => time(),
|
||||
'restarts' => 0
|
||||
];
|
||||
|
||||
custom_log("[WORKER_POOL] Worker {$id} spawned con PID {$pid}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private function supervise() {
|
||||
custom_log("[WORKER_POOL] Iniciando supervisión de workers");
|
||||
|
||||
while ($this->running) {
|
||||
// Verificar estado de cada worker
|
||||
foreach ($this->workers as $id => $info) {
|
||||
$status = pcntl_waitpid($info['pid'], $exitStatus, WNOHANG);
|
||||
|
||||
if ($status > 0) {
|
||||
// Worker terminó
|
||||
$exitCode = pcntl_wexitstatus($exitStatus);
|
||||
custom_log("[WORKER_POOL] Worker {$id} (PID {$info['pid']}) terminó con código {$exitCode}");
|
||||
|
||||
// Reiniciar worker si el pool sigue corriendo
|
||||
if ($this->running) {
|
||||
custom_log("[WORKER_POOL] Reiniciando worker {$id}...");
|
||||
$this->workers[$id]['restarts']++;
|
||||
|
||||
// Esperar un poco antes de reiniciar
|
||||
sleep(1);
|
||||
|
||||
$this->spawnWorker($id);
|
||||
}
|
||||
} elseif ($status < 0) {
|
||||
// Error al verificar estado
|
||||
custom_log("[WORKER_POOL] Error al verificar worker {$id}");
|
||||
}
|
||||
}
|
||||
|
||||
// Procesar señales
|
||||
pcntl_signal_dispatch();
|
||||
|
||||
// Esperar antes de la siguiente verificación
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
custom_log("[WORKER_POOL] Supervisión detenida");
|
||||
}
|
||||
|
||||
public function handleShutdown($signal) {
|
||||
custom_log("[WORKER_POOL] Señal {$signal} recibida, deteniendo pool...");
|
||||
$this->running = false;
|
||||
|
||||
// Enviar señal de terminación a todos los workers
|
||||
foreach ($this->workers as $id => $info) {
|
||||
custom_log("[WORKER_POOL] Enviando SIGTERM a worker {$id} (PID {$info['pid']})");
|
||||
posix_kill($info['pid'], SIGTERM);
|
||||
}
|
||||
|
||||
// Esperar a que todos los workers terminen
|
||||
custom_log("[WORKER_POOL] Esperando a que los workers terminen...");
|
||||
foreach ($this->workers as $id => $info) {
|
||||
pcntl_waitpid($info['pid'], $status);
|
||||
custom_log("[WORKER_POOL] Worker {$id} terminado");
|
||||
}
|
||||
|
||||
custom_log("[WORKER_POOL] Pool detenido completamente");
|
||||
}
|
||||
|
||||
public function getStats() {
|
||||
$stats = [
|
||||
'total_workers' => $this->maxWorkers,
|
||||
'workers' => []
|
||||
];
|
||||
|
||||
foreach ($this->workers as $id => $info) {
|
||||
$stats['workers'][$id] = [
|
||||
'pid' => $info['pid'],
|
||||
'uptime' => time() - $info['started'],
|
||||
'restarts' => $info['restarts']
|
||||
];
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user