queueManager = new VQueueManager(); $this->logger = VLogger::getInstance(); } /** * Start all workers */ public function startWorkers() { echo "Starting EasyStream Queue Workers...\n"; echo str_repeat("=", 50) . "\n"; // Start video processing workers $this->startVideoWorkers(2); // Start general workers $this->startGeneralWorkers(1); // Schedule cleanup jobs $this->scheduleCleanupJobs(); echo "\nAll workers started successfully!\n"; echo "Press Ctrl+C to stop all workers\n\n"; // Keep script running $this->monitorWorkers(); } /** * Start video processing workers * @param int $count Number of workers to start */ private function startVideoWorkers($count) { echo "Starting {$count} video processing workers...\n"; for ($i = 1; $i <= $count; $i++) { $cmd = "php f_core/f_workers/queue-worker.php video_processing > logs/video_worker_{$i}.log 2>&1 &"; if (PHP_OS_FAMILY === 'Windows') { $cmd = "start /B php f_core/f_workers/queue-worker.php video_processing > logs/video_worker_{$i}.log 2>&1"; } $pid = $this->executeCommand($cmd); if ($pid) { $this->workers[] = [ 'type' => 'video_processing', 'id' => $i, 'pid' => $pid, 'started' => time() ]; echo " ✓ Video worker {$i} started (PID: {$pid})\n"; } else { echo " ✗ Failed to start video worker {$i}\n"; } } } /** * Start general workers * @param int $count Number of workers to start */ private function startGeneralWorkers($count) { echo "Starting {$count} general workers...\n"; for ($i = 1; $i <= $count; $i++) { $cmd = "php f_core/f_workers/queue-worker.php default notifications > logs/general_worker_{$i}.log 2>&1 &"; if (PHP_OS_FAMILY === 'Windows') { $cmd = "start /B php f_core/f_workers/queue-worker.php default notifications > logs/general_worker_{$i}.log 2>&1"; } $pid = $this->executeCommand($cmd); if ($pid) { $this->workers[] = [ 'type' => 'general', 'id' => $i, 'pid' => $pid, 'started' => time() ]; echo " ✓ General worker {$i} started (PID: {$pid})\n"; } else { echo " ✗ Failed to start general worker {$i}\n"; } } } /** * Schedule cleanup jobs */ private function scheduleCleanupJobs() { echo "Scheduling cleanup jobs...\n"; // Schedule daily cleanup at 2 AM $cleanupData = [ 'type' => 'full', 'log_retention_days' => 30, 'temp_file_max_age_hours' => 24, 'session_max_age_hours' => 168, 'failed_upload_max_age_hours' => 48, 'analytics_retention_days' => 90, 'queue_retention_hours' => 24 ]; // Calculate delay until 2 AM tomorrow $now = time(); $tomorrow2AM = strtotime('tomorrow 2:00 AM'); $delay = $tomorrow2AM - $now; $jobId = $this->queueManager->enqueue('CleanupJob', $cleanupData, 'maintenance', $delay, 1); if ($jobId) { echo " ✓ Daily cleanup job scheduled (Job ID: {$jobId})\n"; echo " Next run: " . date('Y-m-d H:i:s', $tomorrow2AM) . "\n"; } else { echo " ✗ Failed to schedule cleanup job\n"; } // Schedule weekly database optimization $dbOptimizeData = [ 'type' => 'database' ]; // Calculate delay until Sunday 3 AM $nextSunday3AM = strtotime('next Sunday 3:00 AM'); $weeklyDelay = $nextSunday3AM - $now; $weeklyJobId = $this->queueManager->enqueue('CleanupJob', $dbOptimizeData, 'maintenance', $weeklyDelay, 1); if ($weeklyJobId) { echo " ✓ Weekly database optimization scheduled (Job ID: {$weeklyJobId})\n"; echo " Next run: " . date('Y-m-d H:i:s', $nextSunday3AM) . "\n"; } } /** * Monitor workers and restart if needed */ private function monitorWorkers() { while (true) { sleep(30); // Check every 30 seconds foreach ($this->workers as $index => $worker) { if (!$this->isProcessRunning($worker['pid'])) { echo "Worker {$worker['type']}_{$worker['id']} (PID: {$worker['pid']}) has stopped. Restarting...\n"; // Restart the worker $this->restartWorker($worker, $index); } } // Log worker status every 5 minutes if (time() % 300 === 0) { $this->logWorkerStatus(); } } } /** * Restart a worker * @param array $worker Worker info * @param int $index Worker index */ private function restartWorker($worker, $index) { if ($worker['type'] === 'video_processing') { $cmd = "php f_core/f_workers/queue-worker.php video_processing > logs/video_worker_{$worker['id']}.log 2>&1 &"; } else { $cmd = "php f_core/f_workers/queue-worker.php default notifications > logs/general_worker_{$worker['id']}.log 2>&1 &"; } if (PHP_OS_FAMILY === 'Windows') { $cmd = str_replace(' &', '', $cmd); $cmd = "start /B " . $cmd; } $pid = $this->executeCommand($cmd); if ($pid) { $this->workers[$index]['pid'] = $pid; $this->workers[$index]['started'] = time(); echo " ✓ Worker restarted with PID: {$pid}\n"; } else { echo " ✗ Failed to restart worker\n"; } } /** * Execute command and return PID * @param string $cmd Command to execute * @return int|false PID or false on failure */ private function executeCommand($cmd) { if (PHP_OS_FAMILY === 'Windows') { pclose(popen($cmd, 'r')); return true; // Windows doesn't easily return PID } else { $output = shell_exec($cmd . ' echo $!'); return $output ? (int)trim($output) : false; } } /** * Check if process is running * @param int $pid Process ID * @return bool True if running */ private function isProcessRunning($pid) { if (PHP_OS_FAMILY === 'Windows') { $output = shell_exec("tasklist /FI \"PID eq {$pid}\" 2>NUL"); return strpos($output, (string)$pid) !== false; } else { return file_exists("/proc/{$pid}"); } } /** * Log worker status */ private function logWorkerStatus() { $runningWorkers = count($this->workers); $queueStats = $this->queueManager->getQueueStatistics(); $this->logger->info('Worker status check', [ 'running_workers' => $runningWorkers, 'queue_stats' => $queueStats, 'uptime' => time() - $this->workers[0]['started'] ]); } /** * Stop all workers */ public function stopWorkers() { echo "Stopping all workers...\n"; foreach ($this->workers as $worker) { if (PHP_OS_FAMILY === 'Windows') { shell_exec("taskkill /PID {$worker['pid']} /F 2>NUL"); } else { shell_exec("kill {$worker['pid']} 2>/dev/null"); } echo " ✓ Stopped worker {$worker['type']}_{$worker['id']} (PID: {$worker['pid']})\n"; } echo "All workers stopped.\n"; } /** * Show help */ public function showHelp() { echo "\nEasyStream Queue Workers Manager\n"; echo str_repeat("=", 40) . "\n\n"; echo "Usage: php start-workers.php [command]\n\n"; echo "Commands:\n"; echo " start Start all workers (default)\n"; echo " stop Stop all workers\n"; echo " status Show worker status\n"; echo " help Show this help\n\n"; echo "Examples:\n"; echo " php start-workers.php\n"; echo " php start-workers.php start\n"; echo " php start-workers.php stop\n\n"; } /** * Show worker status */ public function showStatus() { echo "EasyStream Workers Status\n"; echo str_repeat("=", 30) . "\n\n"; $queueStats = $this->queueManager->getQueueStatistics(); $health = $this->queueManager->healthCheck(); echo "System Health: " . strtoupper($health['status']) . "\n"; echo "Backend: " . $health['backend'] . "\n\n"; if (!empty($queueStats)) { echo "Queue Statistics:\n"; foreach ($queueStats as $queue => $stats) { echo " {$queue}:\n"; echo " Pending: " . ($stats['pending'] ?? 0) . "\n"; echo " Processing: " . ($stats['processing'] ?? 0) . "\n"; echo " Completed: " . ($stats['completed'] ?? 0) . "\n"; echo " Failed: " . ($stats['failed'] ?? 0) . "\n\n"; } } } } // CLI execution if (php_sapi_name() === 'cli') { $manager = new WorkerManager(); $command = $argv[1] ?? 'start'; // Handle shutdown signals if (function_exists('pcntl_signal')) { pcntl_signal(SIGTERM, function() use ($manager) { $manager->stopWorkers(); exit(0); }); pcntl_signal(SIGINT, function() use ($manager) { $manager->stopWorkers(); exit(0); }); } switch ($command) { case 'start': $manager->startWorkers(); break; case 'stop': $manager->stopWorkers(); break; case 'status': $manager->showStatus(); break; case 'help': case '--help': case '-h': $manager->showHelp(); break; default: echo "Unknown command: {$command}\n"; $manager->showHelp(); exit(1); } } ?>