feat(Production): Complete production deployment infrastructure

- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
This commit is contained in:
2025-10-25 19:18:37 +02:00
parent caa85db796
commit fc3d7e6357
83016 changed files with 378904 additions and 20919 deletions

View File

@@ -17,7 +17,8 @@ final readonly class DeadLetterQueueCommands
{
public function __construct(
private DeadLetterManager $deadLetterManager
) {}
) {
}
#[ConsoleCommand(name: 'queue:failed', description: 'List failed jobs in dead letter queues')]
public function listFailedJobs(ConsoleInput $input, ConsoleOutput $output): int
@@ -35,6 +36,7 @@ final readonly class DeadLetterQueueCommands
if (empty($failedJobs)) {
$output->writeLine("✅ No failed jobs found");
return 0;
}
@@ -60,9 +62,10 @@ final readonly class DeadLetterQueueCommands
public function retryJob(ConsoleInput $input, ConsoleOutput $output): int
{
$jobId = $input->getArgument('job_id');
if (!$jobId) {
if (! $jobId) {
$output->writeLine("❌ Job ID is required");
$output->writeLine("Usage: queue:retry <job_id>");
return 1;
}
@@ -72,6 +75,7 @@ final readonly class DeadLetterQueueCommands
$output->writeLine("✅ Job {$jobId} successfully retried");
} else {
$output->writeLine("❌ Failed to retry job {$jobId}");
return 1;
}
@@ -82,9 +86,10 @@ final readonly class DeadLetterQueueCommands
public function retryAllJobs(ConsoleInput $input, ConsoleOutput $output): int
{
$queueName = $input->getArgument('queue_name');
if (!$queueName) {
if (! $queueName) {
$output->writeLine("❌ Queue name is required");
$output->writeLine("Usage: queue:retry-all <queue_name>");
return 1;
}
@@ -100,16 +105,18 @@ final readonly class DeadLetterQueueCommands
public function clearDeadLetterQueue(ConsoleInput $input, ConsoleOutput $output): int
{
$queueName = $input->getArgument('queue_name');
if (!$queueName) {
if (! $queueName) {
$output->writeLine("❌ Queue name is required");
$output->writeLine("Usage: queue:clear-failed <queue_name>");
return 1;
}
$confirm = $input->getOption('force', false);
if (!$confirm) {
if (! $confirm) {
$output->writeLine("⚠️ This will permanently delete all failed jobs in queue '{$queueName}'");
$output->writeLine("Use --force to confirm");
return 1;
}
@@ -131,6 +138,7 @@ final readonly class DeadLetterQueueCommands
if (empty($stats)) {
$output->writeLine("✅ No dead letter queues found");
return 0;
}
@@ -153,16 +161,18 @@ final readonly class DeadLetterQueueCommands
public function deleteJob(ConsoleInput $input, ConsoleOutput $output): int
{
$jobId = $input->getArgument('job_id');
if (!$jobId) {
if (! $jobId) {
$output->writeLine("❌ Job ID is required");
$output->writeLine("Usage: queue:delete-failed <job_id>");
return 1;
}
$confirm = $input->getOption('force', false);
if (!$confirm) {
if (! $confirm) {
$output->writeLine("⚠️ This will permanently delete the failed job {$jobId}");
$output->writeLine("Use --force to confirm");
return 1;
}
@@ -172,9 +182,10 @@ final readonly class DeadLetterQueueCommands
$output->writeLine("✅ Job {$jobId} successfully deleted");
} else {
$output->writeLine("❌ Failed to delete job {$jobId} (job not found)");
return 1;
}
return 0;
}
}
}

View File

@@ -4,10 +4,9 @@ declare(strict_types=1);
namespace App\Framework\Queue\Commands;
use App\Framework\Console\ConsoleCommand;
use App\Framework\Attributes\ConsoleCommand as ConsoleCommandAttribute;
use App\Framework\Queue\Contracts\JobBatchManagerInterface;
use App\Framework\Queue\ValueObjects\JobBatchStatus;
use App\Framework\Attributes\ConsoleCommand as ConsoleCommandAttribute;
/**
* Console commands for job batch management
@@ -16,7 +15,8 @@ final readonly class JobBatchCommands
{
public function __construct(
private JobBatchManagerInterface $batchManager
) {}
) {
}
#[ConsoleCommandAttribute(name: 'batch:list', description: 'List job batches')]
public function listBatches(string $status = 'all', int $limit = 20): void
@@ -30,7 +30,7 @@ final readonly class JobBatchCommands
}
// Sort by created_at desc
usort($batches, fn($a, $b) => $b->createdAt?->getTimestamp() <=> $a->createdAt?->getTimestamp());
usort($batches, fn ($a, $b) => $b->createdAt?->getTimestamp() <=> $a->createdAt?->getTimestamp());
$batches = array_slice($batches, 0, $limit);
} else {
try {
@@ -38,13 +38,15 @@ final readonly class JobBatchCommands
$batches = $this->batchManager->getBatchesByStatus($batchStatus, $limit);
} catch (\ValueError) {
echo "❌ Invalid status: {$status}. Valid statuses: " .
implode(', ', array_map(fn($s) => $s->value, JobBatchStatus::cases())) . "\n";
implode(', ', array_map(fn ($s) => $s->value, JobBatchStatus::cases())) . "\n";
return;
}
}
if (empty($batches)) {
echo "No batches found" . ($status !== 'all' ? " with status: {$status}" : '') . "\n";
return;
}
@@ -82,8 +84,9 @@ final readonly class JobBatchCommands
{
$batch = $this->batchManager->getBatch($batchId);
if (!$batch) {
if (! $batch) {
echo "❌ Batch not found: {$batchId}\n";
return;
}
@@ -116,7 +119,7 @@ final readonly class JobBatchCommands
}
echo "\n";
if (!empty($batch->options)) {
if (! empty($batch->options)) {
echo "Options:\n";
foreach ($batch->options as $key => $value) {
echo " {$key}: " . (is_array($value) ? json_encode($value) : $value) . "\n";
@@ -135,13 +138,15 @@ final readonly class JobBatchCommands
{
$batch = $this->batchManager->getBatch($batchId);
if (!$batch) {
if (! $batch) {
echo "❌ Batch not found: {$batchId}\n";
return;
}
if ($batch->isFinished()) {
echo "❌ Cannot cancel batch: already finished with status {$batch->status->getDisplayName()}\n";
return;
}
@@ -161,6 +166,7 @@ final readonly class JobBatchCommands
if (empty($stats)) {
echo "No batch statistics available\n";
return;
}
@@ -207,6 +213,7 @@ final readonly class JobBatchCommands
{
if ($olderThanDays < 1) {
echo "❌ Days must be at least 1\n";
return;
}
@@ -228,6 +235,7 @@ final readonly class JobBatchCommands
if (empty($progress)) {
echo "❌ Batch not found: {$batchId}\n";
return;
}
@@ -256,4 +264,4 @@ final readonly class JobBatchCommands
echo "✅ Batch completed\n";
}
}
}
}

View File

@@ -7,9 +7,9 @@ namespace App\Framework\Queue\Commands;
use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ExitCode;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Performance\MemoryMonitor;
use App\Framework\Queue\Services\JobCleanupService;
use App\Framework\Queue\Services\JobMemoryManager;
use App\Framework\Performance\MemoryMonitor;
final readonly class JobCleanupCommands
{
@@ -17,7 +17,8 @@ final readonly class JobCleanupCommands
private JobCleanupService $cleanupService,
private JobMemoryManager $memoryManager,
private MemoryMonitor $memoryMonitor
) {}
) {
}
#[ConsoleCommand(name: 'queue:cleanup:all', description: 'Run comprehensive queue cleanup with default retention periods')]
public function runComprehensiveCleanup(): ExitCode
@@ -46,6 +47,7 @@ final readonly class JobCleanupCommands
if ($stats['total_eligible'] === 0) {
echo "✅ No data eligible for cleanup\n";
return ExitCode::SUCCESS;
}
@@ -67,19 +69,22 @@ final readonly class JobCleanupCommands
echo " • Memory used: {$results['memory_used']}\n";
echo " • Peak memory: {$results['memory_peak']}\n\n";
if (!empty($results['errors'])) {
if (! empty($results['errors'])) {
echo "⚠️ Errors occurred:\n";
foreach ($results['errors'] as $error) {
echo "{$error}\n";
}
return ExitCode::GENERAL_ERROR;
}
echo "✅ Cleanup completed successfully!\n";
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -92,6 +97,7 @@ final readonly class JobCleanupCommands
try {
if ($days < 1) {
echo "❌ Days must be at least 1\n";
return ExitCode::INVALID_ARGUMENT;
}
@@ -108,6 +114,7 @@ final readonly class JobCleanupCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -120,6 +127,7 @@ final readonly class JobCleanupCommands
try {
if ($days < 1) {
echo "❌ Days must be at least 1\n";
return ExitCode::INVALID_ARGUMENT;
}
@@ -136,6 +144,7 @@ final readonly class JobCleanupCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -148,6 +157,7 @@ final readonly class JobCleanupCommands
try {
if ($days < 1) {
echo "❌ Days must be at least 1\n";
return ExitCode::INVALID_ARGUMENT;
}
@@ -164,6 +174,7 @@ final readonly class JobCleanupCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -176,6 +187,7 @@ final readonly class JobCleanupCommands
try {
if ($days < 1) {
echo "❌ Days must be at least 1\n";
return ExitCode::INVALID_ARGUMENT;
}
@@ -192,6 +204,7 @@ final readonly class JobCleanupCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -229,7 +242,7 @@ final readonly class JobCleanupCommands
foreach ($recommendations['recommendations'] as $rec) {
echo "\n 📌 {$rec['type']}:\n";
echo " {$rec['message']}\n";
if (!empty($rec['actions'])) {
if (! empty($rec['actions'])) {
echo " Actions:\n";
foreach ($rec['actions'] as $action) {
echo "{$action}\n";
@@ -241,6 +254,7 @@ final readonly class JobCleanupCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -277,7 +291,7 @@ final readonly class JobCleanupCommands
foreach ($recommendations['recommendations'] as $rec) {
echo "\n {$rec['type']}:\n";
echo " {$rec['message']}\n";
if (!empty($rec['actions'])) {
if (! empty($rec['actions'])) {
echo " Suggested actions:\n";
foreach ($rec['actions'] as $action) {
echo "{$action}\n";
@@ -289,6 +303,7 @@ final readonly class JobCleanupCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -322,7 +337,8 @@ final readonly class JobCleanupCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
}
}

View File

@@ -12,7 +12,8 @@ final readonly class JobMetricsCommands
{
public function __construct(
private JobMetricsManagerInterface $metricsManager
) {}
) {
}
#[ConsoleCommand(name: 'queue:metrics:overview', description: 'Show system-wide queue metrics overview')]
public function systemOverview(): ExitCode
@@ -47,7 +48,7 @@ final readonly class JobMetricsCommands
foreach ($overview['queue_metrics'] as $queueName => $metrics) {
$healthIcon = $metrics->isHealthy() ? '✅' : '⚠️';
$bottlenecks = $metrics->getBottleneckIndicators();
$bottleneckText = !empty($bottlenecks) ? ' (' . implode(', ', $bottlenecks) . ')' : '';
$bottleneckText = ! empty($bottlenecks) ? ' (' . implode(', ', $bottlenecks) . ')' : '';
echo " {$healthIcon} {$queueName}: {$metrics->totalJobs} jobs, {$metrics->successRate->getValue()}% success{$bottleneckText}\n";
}
@@ -55,6 +56,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -93,7 +95,7 @@ final readonly class JobMetricsCommands
// Bottlenecks
$bottlenecks = $metrics->getBottleneckIndicators();
if (!empty($bottlenecks)) {
if (! empty($bottlenecks)) {
echo "⚠️ Bottleneck Indicators:\n";
foreach ($bottlenecks as $bottleneck) {
echo " - " . str_replace('_', ' ', ucfirst($bottleneck)) . "\n";
@@ -106,6 +108,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -116,8 +119,9 @@ final readonly class JobMetricsCommands
try {
$metrics = $this->metricsManager->getJobMetrics($jobId);
if (!$metrics) {
if (! $metrics) {
echo "❌ No metrics found for job: {$jobId}\n";
return ExitCode::GENERAL_ERROR;
}
@@ -160,7 +164,7 @@ final readonly class JobMetricsCommands
}
// Metadata
if (!empty($metrics->metadata)) {
if (! empty($metrics->metadata)) {
echo "\n📝 Metadata:\n";
foreach ($metrics->metadata as $key => $value) {
echo " {$key}: " . json_encode($value) . "\n";
@@ -170,6 +174,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -185,6 +190,7 @@ final readonly class JobMetricsCommands
if (empty($slowJobs)) {
echo " No jobs found\n";
return ExitCode::SUCCESS;
}
@@ -202,6 +208,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -217,6 +224,7 @@ final readonly class JobMetricsCommands
if (empty($memoryJobs)) {
echo " No jobs found\n";
return ExitCode::SUCCESS;
}
@@ -234,6 +242,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -249,6 +258,7 @@ final readonly class JobMetricsCommands
if (empty($failedJobs)) {
echo " No failed jobs found\n";
return ExitCode::SUCCESS;
}
@@ -265,6 +275,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -301,6 +312,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -333,6 +345,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -355,6 +368,7 @@ final readonly class JobMetricsCommands
return ExitCode::SUCCESS;
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -370,4 +384,4 @@ final readonly class JobMetricsCommands
default => '❓'
};
}
}
}

View File

@@ -6,8 +6,8 @@ namespace App\Framework\Queue\Commands;
use App\Framework\Attributes\ConsoleCommand;
use App\Framework\Console\ConsoleOutput;
use App\Framework\Queue\Services\ProgressManager;
use App\Framework\Queue\Entities\JobProgressEntry;
use App\Framework\Queue\Services\ProgressManager;
/**
* Console commands for managing job progress
@@ -16,15 +16,17 @@ final readonly class ProgressCommands
{
public function __construct(
private ProgressManager $progressManager
) {}
) {
}
#[ConsoleCommand(name: 'queue:progress:show', description: 'Show current progress for a job')]
public function showProgress(string $jobId, ConsoleOutput $output): void
{
$progress = $this->progressManager->getJobProgress($jobId);
if (!$progress) {
if (! $progress) {
$output->writeln("<error>No progress found for job: {$jobId}</error>");
return;
}
@@ -50,6 +52,7 @@ final readonly class ProgressCommands
if (empty($history)) {
$output->writeln("<error>No progress history found for job: {$jobId}</error>");
return;
}
@@ -67,9 +70,13 @@ final readonly class ProgressCommands
}
$status = [];
if ($entry->isCompleted) $status[] = 'Completed';
if ($entry->isFailed) $status[] = 'Failed';
if (!empty($status)) {
if ($entry->isCompleted) {
$status[] = 'Completed';
}
if ($entry->isFailed) {
$status[] = 'Failed';
}
if (! empty($status)) {
$output->writeln("Status: " . implode(', ', $status));
}
@@ -84,6 +91,7 @@ final readonly class ProgressCommands
if (empty($recentJobs)) {
$output->writeln("<info>No recent job progress updates found</info>");
return;
}
@@ -102,9 +110,13 @@ final readonly class ProgressCommands
}
$status = [];
if ($entry->isCompleted) $status[] = 'Completed';
if ($entry->isFailed) $status[] = 'Failed';
if (!empty($status)) {
if ($entry->isCompleted) {
$status[] = 'Completed';
}
if ($entry->isFailed) {
$status[] = 'Failed';
}
if (! empty($status)) {
$output->writeln("Status: " . implode(', ', $status));
}
@@ -117,6 +129,7 @@ final readonly class ProgressCommands
{
if ($percentage < 0 || $percentage > 100) {
$output->writeln("<error>Percentage must be between 0 and 100</error>");
return;
}
@@ -124,6 +137,7 @@ final readonly class ProgressCommands
if (empty($jobs)) {
$output->writeln("<info>No jobs found above {$percentage}% progress</info>");
return;
}
@@ -138,9 +152,13 @@ final readonly class ProgressCommands
$output->writeln("Updated: {$entry->updatedAt}");
$status = [];
if ($entry->isCompleted) $status[] = 'Completed';
if ($entry->isFailed) $status[] = 'Failed';
if (!empty($status)) {
if ($entry->isCompleted) {
$status[] = 'Completed';
}
if ($entry->isFailed) {
$status[] = 'Failed';
}
if (! empty($status)) {
$output->writeln("Status: " . implode(', ', $status));
}
@@ -163,6 +181,7 @@ final readonly class ProgressCommands
if (empty($idArray)) {
$output->writeln("<error>No job IDs provided</error>");
return;
}
@@ -170,6 +189,7 @@ final readonly class ProgressCommands
if (empty($progressData)) {
$output->writeln("<error>No progress found for any of the provided job IDs</error>");
return;
}
@@ -191,4 +211,4 @@ final readonly class ProgressCommands
$output->writeln(str_repeat('-', 40));
}
}
}
}

View File

@@ -6,13 +6,13 @@ namespace App\Framework\Queue\Commands;
use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ExitCode;
use App\Framework\Queue\Services\WorkerRegistry;
use App\Framework\Queue\Services\WorkerHealthCheckService;
use App\Framework\Queue\Services\JobDistributionService;
use App\Framework\Queue\Services\FailoverRecoveryService;
use App\Framework\Queue\Interfaces\DistributedLockInterface;
use App\Framework\Queue\ValueObjects\WorkerId;
use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Queue\Interfaces\DistributedLockInterface;
use App\Framework\Queue\Services\FailoverRecoveryService;
use App\Framework\Queue\Services\JobDistributionService;
use App\Framework\Queue\Services\WorkerHealthCheckService;
use App\Framework\Queue\Services\WorkerRegistry;
use App\Framework\Queue\ValueObjects\WorkerId;
/**
* Console Commands für Worker Management
@@ -25,7 +25,8 @@ final readonly class WorkerCommands
private JobDistributionService $jobDistributionService,
private FailoverRecoveryService $failoverRecoveryService,
private DistributedLockInterface $distributedLock
) {}
) {
}
#[ConsoleCommand(name: 'worker:list', description: 'List all registered workers with their status')]
public function listWorkers(bool $active = true, bool $detailed = false): ExitCode
@@ -39,6 +40,7 @@ final readonly class WorkerCommands
if (empty($workers)) {
echo " No workers found\n";
return ExitCode::SUCCESS;
}
@@ -51,7 +53,7 @@ final readonly class WorkerCommands
echo "{$status} {$worker->hostname}:{$worker->processId}\n";
echo " ID: {$worker->id->toString()}\n";
echo " Load: {$worker->currentJobs}/{$worker->maxJobs} ({$load}%)\n";
echo " Queues: " . implode(', ', array_map(fn($q) => $q->toString(), $worker->queues)) . "\n";
echo " Queues: " . implode(', ', array_map(fn ($q) => $q->toString(), $worker->queues)) . "\n";
if ($detailed) {
echo " CPU: {$worker->cpuUsage->getValue()}%\n";
@@ -67,6 +69,7 @@ final readonly class WorkerCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -103,14 +106,14 @@ final readonly class WorkerCommands
echo "{$statusIcon} {$workerHealth['hostname']}:{$workerHealth['process_id']}\n";
echo " Status: {$workerHealth['status']} (Score: {$workerHealth['score']})\n";
if (!empty($workerHealth['issues'])) {
if (! empty($workerHealth['issues'])) {
echo " Issues:\n";
foreach ($workerHealth['issues'] as $issue) {
echo "{$issue}\n";
}
}
if (!empty($workerHealth['warnings'])) {
if (! empty($workerHealth['warnings'])) {
echo " Warnings:\n";
foreach ($workerHealth['warnings'] as $warning) {
echo " ⚠️ {$warning}\n";
@@ -133,6 +136,7 @@ final readonly class WorkerCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -190,7 +194,7 @@ final readonly class WorkerCommands
echo " Load Variance: " . ($health['load_variance'] ?? 0) . "%\n";
echo " Availability: " . ($health['availability_ratio'] ?? 0) . "%\n";
if (!empty($health['issues'])) {
if (! empty($health['issues'])) {
echo " Issues:\n";
foreach ($health['issues'] as $issue) {
echo "{$issue}\n";
@@ -201,6 +205,7 @@ final readonly class WorkerCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -248,7 +253,7 @@ final readonly class WorkerCommands
echo " Duration: {$results['duration_seconds']}s\n";
if (!empty($results['errors'])) {
if (! empty($results['errors'])) {
echo "\n❌ Errors:\n";
foreach ($results['errors'] as $error) {
echo "{$error}\n";
@@ -262,6 +267,7 @@ final readonly class WorkerCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -283,7 +289,7 @@ final readonly class WorkerCommands
echo " Oldest Lock: " . ($lockStats['oldest_lock'] ?? 'None') . "\n";
echo " Newest Lock: " . ($lockStats['newest_lock'] ?? 'None') . "\n\n";
if ($detailed && !empty($lockStats['top_lock_keys'])) {
if ($detailed && ! empty($lockStats['top_lock_keys'])) {
echo "🔑 Top Lock Keys:\n";
foreach ($lockStats['top_lock_keys'] as $keyInfo) {
echo " {$keyInfo['lock_key']}: {$keyInfo['count']} locks\n";
@@ -300,6 +306,7 @@ final readonly class WorkerCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -332,7 +339,7 @@ final readonly class WorkerCommands
echo " Expired Locks: {$metrics['expired_locks']}\n";
}
if (!empty($resilience['factors'])) {
if (! empty($resilience['factors'])) {
echo "\n⚠️ Resilience Factors:\n";
foreach ($resilience['factors'] as $factor) {
echo "{$factor}\n";
@@ -352,6 +359,7 @@ final readonly class WorkerCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -385,6 +393,7 @@ final readonly class WorkerCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
@@ -397,8 +406,9 @@ final readonly class WorkerCommands
try {
$worker = $this->workerRegistry->findById(WorkerId::fromString($workerId));
if (!$worker) {
if (! $worker) {
echo "❌ Worker not found: {$workerId}\n";
return ExitCode::INVALID_ARGUMENT;
}
@@ -422,7 +432,8 @@ final readonly class WorkerCommands
} catch (\Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
return ExitCode::GENERAL_ERROR;
}
}
}
}