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

@@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Framework\Logging;
use App\Framework\CircuitBreaker\CircuitBreaker;
use App\Framework\CircuitBreaker\CircuitBreakerConfig;
use App\Framework\Logging\Handlers\ResilientLogHandler;
use App\Framework\Logging\LogHandler;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;
use App\Framework\Logging\ValueObjects\LogContext;
use PHPUnit\Framework\TestCase;
final class ResilientLogHandlerTest extends TestCase
{
public function test_uses_primary_handler_when_healthy(): void
{
$primary = $this->createMock(LogHandler::class);
$fallback = $this->createMock(LogHandler::class);
$record = $this->createLogRecord();
$primary->expects($this->once())
->method('handle')
->with($record);
$fallback->expects($this->never())
->method('handle');
$handler = new ResilientLogHandler($primary, $fallback);
$handler->handle($record);
}
public function test_uses_fallback_when_primary_fails(): void
{
$primary = $this->createMock(LogHandler::class);
$fallback = $this->createMock(LogHandler::class);
$record = $this->createLogRecord();
$primary->method('handle')
->willThrowException(new \RuntimeException('Primary failed'));
$fallback->expects($this->atLeastOnce())
->method('handle');
$handler = new ResilientLogHandler($primary, $fallback);
$handler->handle($record);
// Should not throw exception
$this->assertTrue(true);
}
public function test_never_throws_exception(): void
{
$primary = $this->createMock(LogHandler::class);
$fallback = $this->createMock(LogHandler::class);
$primary->method('handle')
->willThrowException(new \RuntimeException('Primary failed'));
$fallback->method('handle')
->willThrowException(new \RuntimeException('Fallback failed'));
$handler = new ResilientLogHandler($primary, $fallback);
// Should never throw - uses error_log as last resort
$handler->handle($this->createLogRecord());
$this->assertTrue(true);
}
public function test_circuit_breaker_opens_after_failures(): void
{
$primary = $this->createMock(LogHandler::class);
$fallback = $this->createMock(LogHandler::class);
$circuitBreaker = new CircuitBreaker(
new CircuitBreakerConfig(
name: 'test',
failureThreshold: 3,
successThreshold: 1,
timeout: 60.0
)
);
$primary->method('handle')
->willThrowException(new \RuntimeException('Failed'));
$handler = new ResilientLogHandler($primary, $fallback, $circuitBreaker);
// Trigger failures to open circuit
for ($i = 0; $i < 5; $i++) {
$handler->handle($this->createLogRecord());
}
$this->assertTrue($circuitBreaker->isOpen());
$this->assertFalse($handler->isHealthy());
}
private function createLogRecord(string $message = 'test'): LogRecord
{
return new LogRecord(
level: LogLevel::INFO,
message: $message,
channel: 'test',
context: LogContext::empty(),
timestamp: new \DateTimeImmutable()
);
}
}