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

@@ -2,10 +2,8 @@
declare(strict_types=1);
use App\Framework\Queue\ValueObjects\JobMetrics;
use App\Framework\Queue\ValueObjects\JobId;
use App\Framework\Queue\ValueObjects\QueueName;
use App\Framework\Core\ValueObjects\Percentage;
use App\Framework\Queue\ValueObjects\JobMetrics;
describe('JobMetrics Value Object', function () {
@@ -142,7 +140,7 @@ describe('JobMetrics Value Object', function () {
$metadata = [
'user_id' => 12345,
'email_template' => 'newsletter',
'batch_size' => 1000
'batch_size' => 1000,
];
$metricsWithMetadata = $this->baseMetrics->withMetadata($metadata);
@@ -163,7 +161,7 @@ describe('JobMetrics Value Object', function () {
'user_id' => 123,
'type' => 'email',
'priority' => 'high',
'retry_count' => 2
'retry_count' => 2,
]);
});
@@ -323,7 +321,7 @@ describe('JobMetrics Value Object', function () {
'job_id', 'queue_name', 'status', 'attempts', 'max_attempts',
'execution_time_ms', 'execution_time_seconds', 'memory_usage_bytes',
'memory_usage_mb', 'success_rate', 'duration_seconds', 'error_message',
'created_at', 'started_at', 'completed_at', 'failed_at', 'metadata'
'created_at', 'started_at', 'completed_at', 'failed_at', 'metadata',
];
foreach ($expectedKeys as $key) {
@@ -394,7 +392,7 @@ describe('JobMetrics Value Object', function () {
$complexMetadata = [
'nested' => ['level1' => ['level2' => 'value']],
'array' => [1, 2, 3, 4, 5],
'mixed' => ['string', 42, true, null]
'mixed' => ['string', 42, true, null],
];
$metrics = JobMetrics::create('complex-job', 'data-queue')
@@ -409,12 +407,14 @@ describe('Job Metrics Collection Mock System', function () {
beforeEach(function () {
// Create a mock metrics manager for testing
$this->metricsManager = new class {
$this->metricsManager = new class () {
private array $jobMetrics = [];
private array $queueStats = [];
public function recordJobExecution(string $jobId, float $executionTimeMs, int $memoryUsage): void {
if (!isset($this->jobMetrics[$jobId])) {
public function recordJobExecution(string $jobId, float $executionTimeMs, int $memoryUsage): void
{
if (! isset($this->jobMetrics[$jobId])) {
$this->jobMetrics[$jobId] = JobMetrics::create($jobId, 'default-queue');
}
@@ -422,8 +422,9 @@ describe('Job Metrics Collection Mock System', function () {
->withCompleted($executionTimeMs, $memoryUsage);
}
public function recordJobFailure(string $jobId, string $errorMessage, float $executionTimeMs, int $memoryUsage): void {
if (!isset($this->jobMetrics[$jobId])) {
public function recordJobFailure(string $jobId, string $errorMessage, float $executionTimeMs, int $memoryUsage): void
{
if (! isset($this->jobMetrics[$jobId])) {
$this->jobMetrics[$jobId] = JobMetrics::create($jobId, 'default-queue');
}
@@ -431,12 +432,14 @@ describe('Job Metrics Collection Mock System', function () {
->withFailed($errorMessage, $executionTimeMs, $memoryUsage);
}
public function getJobMetrics(string $jobId): ?JobMetrics {
public function getJobMetrics(string $jobId): ?JobMetrics
{
return $this->jobMetrics[$jobId] ?? null;
}
public function getQueueMetrics(string $queueName): array {
$jobs = array_filter($this->jobMetrics, fn($metrics) => $metrics->queueName === $queueName);
public function getQueueMetrics(string $queueName): array
{
$jobs = array_filter($this->jobMetrics, fn ($metrics) => $metrics->queueName === $queueName);
if (empty($jobs)) {
return [
@@ -446,15 +449,15 @@ describe('Job Metrics Collection Mock System', function () {
'failed_jobs' => 0,
'average_execution_time_ms' => 0.0,
'average_memory_usage_mb' => 0.0,
'success_rate' => 100.0
'success_rate' => 100.0,
];
}
$totalJobs = count($jobs);
$completedJobs = count(array_filter($jobs, fn($m) => $m->isCompleted()));
$failedJobs = count(array_filter($jobs, fn($m) => $m->isFailed()));
$avgExecutionTime = array_sum(array_map(fn($m) => $m->executionTimeMs, $jobs)) / $totalJobs;
$avgMemoryUsage = array_sum(array_map(fn($m) => $m->getMemoryUsageMB(), $jobs)) / $totalJobs;
$completedJobs = count(array_filter($jobs, fn ($m) => $m->isCompleted()));
$failedJobs = count(array_filter($jobs, fn ($m) => $m->isFailed()));
$avgExecutionTime = array_sum(array_map(fn ($m) => $m->executionTimeMs, $jobs)) / $totalJobs;
$avgMemoryUsage = array_sum(array_map(fn ($m) => $m->getMemoryUsageMB(), $jobs)) / $totalJobs;
$successRate = ($completedJobs / $totalJobs) * 100;
return [
@@ -464,11 +467,12 @@ describe('Job Metrics Collection Mock System', function () {
'failed_jobs' => $failedJobs,
'average_execution_time_ms' => round($avgExecutionTime, 2),
'average_memory_usage_mb' => round($avgMemoryUsage, 2),
'success_rate' => round($successRate, 2)
'success_rate' => round($successRate, 2),
];
}
public function getSystemMetrics(): array {
public function getSystemMetrics(): array
{
if (empty($this->jobMetrics)) {
return [
'total_jobs' => 0,
@@ -477,17 +481,17 @@ describe('Job Metrics Collection Mock System', function () {
'running_jobs' => 0,
'overall_success_rate' => 100.0,
'average_execution_time_ms' => 0.0,
'peak_memory_usage_mb' => 0.0
'peak_memory_usage_mb' => 0.0,
];
}
$totalJobs = count($this->jobMetrics);
$completedJobs = count(array_filter($this->jobMetrics, fn($m) => $m->isCompleted()));
$failedJobs = count(array_filter($this->jobMetrics, fn($m) => $m->isFailed()));
$runningJobs = count(array_filter($this->jobMetrics, fn($m) => $m->isRunning()));
$completedJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isCompleted()));
$failedJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isFailed()));
$runningJobs = count(array_filter($this->jobMetrics, fn ($m) => $m->isRunning()));
$overallSuccessRate = ($completedJobs / $totalJobs) * 100;
$avgExecutionTime = array_sum(array_map(fn($m) => $m->executionTimeMs, $this->jobMetrics)) / $totalJobs;
$peakMemoryUsage = max(array_map(fn($m) => $m->getMemoryUsageMB(), $this->jobMetrics));
$avgExecutionTime = array_sum(array_map(fn ($m) => $m->executionTimeMs, $this->jobMetrics)) / $totalJobs;
$peakMemoryUsage = max(array_map(fn ($m) => $m->getMemoryUsageMB(), $this->jobMetrics));
return [
'total_jobs' => $totalJobs,
@@ -496,24 +500,29 @@ describe('Job Metrics Collection Mock System', function () {
'running_jobs' => $runningJobs,
'overall_success_rate' => round($overallSuccessRate, 2),
'average_execution_time_ms' => round($avgExecutionTime, 2),
'peak_memory_usage_mb' => round($peakMemoryUsage, 2)
'peak_memory_usage_mb' => round($peakMemoryUsage, 2),
];
}
public function getTopSlowJobs(int $limit = 10): array {
public function getTopSlowJobs(int $limit = 10): array
{
$jobs = $this->jobMetrics;
usort($jobs, fn($a, $b) => $b->executionTimeMs <=> $a->executionTimeMs);
usort($jobs, fn ($a, $b) => $b->executionTimeMs <=> $a->executionTimeMs);
return array_slice($jobs, 0, $limit);
}
public function getTopMemoryJobs(int $limit = 10): array {
public function getTopMemoryJobs(int $limit = 10): array
{
$jobs = $this->jobMetrics;
usort($jobs, fn($a, $b) => $b->memoryUsageBytes <=> $a->memoryUsageBytes);
usort($jobs, fn ($a, $b) => $b->memoryUsageBytes <=> $a->memoryUsageBytes);
return array_slice($jobs, 0, $limit);
}
public function getJobsByQueue(string $queueName): array {
return array_filter($this->jobMetrics, fn($metrics) => $metrics->queueName === $queueName);
public function getJobsByQueue(string $queueName): array
{
return array_filter($this->jobMetrics, fn ($metrics) => $metrics->queueName === $queueName);
}
};
});
@@ -611,9 +620,11 @@ describe('Job Metrics Collection Mock System', function () {
});
it('handles empty system gracefully', function () {
$emptyManager = new class {
$emptyManager = new class () {
private array $jobMetrics = [];
public function getSystemMetrics(): array {
public function getSystemMetrics(): array
{
return [
'total_jobs' => 0,
'completed_jobs' => 0,
@@ -621,7 +632,7 @@ describe('Job Metrics Collection Mock System', function () {
'running_jobs' => 0,
'overall_success_rate' => 100.0,
'average_execution_time_ms' => 0.0,
'peak_memory_usage_mb' => 0.0
'peak_memory_usage_mb' => 0.0,
];
}
};
@@ -688,4 +699,4 @@ describe('Job Metrics Collection Mock System', function () {
expect($emptyQueue)->toBe([]);
});
});
});
});