- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
372 lines
11 KiB
PHP
372 lines
11 KiB
PHP
<?php
|
|
/*******************************************************************************************************************
|
|
| EasyStream Queue Workers Starter
|
|
| Starts background workers for video processing and system maintenance
|
|
|*******************************************************************************************************************/
|
|
|
|
define('_ISVALID', true);
|
|
|
|
// Include core configuration
|
|
include_once 'f_core/config.core.php';
|
|
|
|
/**
|
|
* Queue Workers Management Script
|
|
*/
|
|
class WorkerManager
|
|
{
|
|
private $queueManager;
|
|
private $logger;
|
|
private $workers = [];
|
|
|
|
public function __construct()
|
|
{
|
|
$this->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);
|
|
}
|
|
}
|
|
?>
|