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,296 @@
<?php
declare(strict_types=1);
use App\Framework\Performance\GarbageCollectionMonitor;
use App\Framework\Performance\ValueObjects\GcStatus;
use App\Framework\Performance\ValueObjects\GcResult;
describe('GarbageCollectionMonitor', function () {
beforeEach(function () {
$this->monitor = new GarbageCollectionMonitor();
});
it('returns current GC status', function () {
$status = $this->monitor->getStatus();
expect($status)->toBeInstanceOf(GcStatus::class);
expect($status->runs)->toBeInt();
expect($status->collected)->toBeInt();
expect($status->threshold)->toBeGreaterThan(0);
expect($status->roots)->toBeInt();
});
it('gets number of GC runs', function () {
$runs = $this->monitor->getRuns();
expect($runs)->toBeInt();
expect($runs)->toBeGreaterThanOrEqual(0);
});
it('gets number of collected cycles', function () {
$collected = $this->monitor->getCollected();
expect($collected)->toBeInt();
expect($collected)->toBeGreaterThanOrEqual(0);
});
it('gets GC threshold', function () {
$threshold = $this->monitor->getThreshold();
expect($threshold)->toBeInt();
expect($threshold)->toBeGreaterThan(0);
});
it('checks if GC is running', function () {
$isRunning = $this->monitor->isRunning();
expect($isRunning)->toBeBool();
});
it('checks if GC is enabled', function () {
$isEnabled = $this->monitor->isEnabled();
expect($isEnabled)->toBeBool();
});
it('can force garbage collection', function () {
// Create some circular references to collect
$obj1 = new stdClass();
$obj2 = new stdClass();
$obj1->ref = $obj2;
$obj2->ref = $obj1;
unset($obj1, $obj2);
$result = $this->monitor->forceCollection();
expect($result)->toBeInstanceOf(GcResult::class);
expect($result->collected)->toBeInt();
expect($result->duration)->toBeInstanceOf(App\Framework\Core\ValueObjects\Duration::class);
expect($result->memoryFreed)->toBeInstanceOf(App\Framework\Core\ValueObjects\Byte::class);
expect($result->statusBefore)->toBeInstanceOf(GcStatus::class);
expect($result->statusAfter)->toBeInstanceOf(GcStatus::class);
expect($result->timestamp)->toBeInstanceOf(App\Framework\Core\ValueObjects\Timestamp::class);
});
it('provides efficiency metrics', function () {
$metrics = $this->monitor->getEfficiencyMetrics();
expect($metrics)->toHaveKeys([
'collection_rate',
'threshold_ratio',
'is_healthy',
'runs',
'collected',
'roots',
'threshold',
]);
expect($metrics['collection_rate'])->toBeFloat();
expect($metrics['threshold_ratio'])->toBeFloat();
expect($metrics['is_healthy'])->toBeBool();
});
it('can take GC snapshot', function () {
$snapshot = $this->monitor->takeSnapshot('test_checkpoint');
expect($snapshot)->toHaveKeys(['label', 'timestamp', 'status', 'efficiency']);
expect($snapshot['label'])->toBe('test_checkpoint');
expect($snapshot['status'])->toBeArray();
expect($snapshot['efficiency'])->toBeArray();
});
it('can enable and disable GC', function () {
$this->monitor->disable();
expect(gc_enabled())->toBeFalse();
$this->monitor->enable();
expect(gc_enabled())->toBeTrue();
});
});
describe('GcStatus', function () {
it('creates from gc_status array', function () {
$status = GcStatus::fromGcStatus(gc_status());
expect($status)->toBeInstanceOf(GcStatus::class);
expect($status->runs)->toBeInt();
expect($status->collected)->toBeInt();
expect($status->threshold)->toBeInt();
expect($status->roots)->toBeInt();
});
it('creates current GC status', function () {
$status = GcStatus::current();
expect($status)->toBeInstanceOf(GcStatus::class);
});
it('calculates collection efficiency', function () {
$status = new GcStatus(runs: 10, collected: 50, threshold: 10001, roots: 100);
$efficiency = $status->getCollectionEfficiency();
expect($efficiency)->toBe(5.0); // 50 / 10
});
it('returns zero efficiency when no runs', function () {
$status = new GcStatus(runs: 0, collected: 0, threshold: 10001, roots: 0);
expect($status->getCollectionEfficiency())->toBe(0.0);
});
it('calculates threshold utilization', function () {
$status = new GcStatus(runs: 10, collected: 50, threshold: 1000, roots: 900);
$utilization = $status->getThresholdUtilization();
expect($utilization)->toBe(0.9); // 900 / 1000
});
it('checks if near threshold', function () {
$nearThreshold = new GcStatus(runs: 10, collected: 50, threshold: 1000, roots: 950);
$notNearThreshold = new GcStatus(runs: 10, collected: 50, threshold: 1000, roots: 500);
expect($nearThreshold->isNearThreshold(0.9))->toBeTrue();
expect($notNearThreshold->isNearThreshold(0.9))->toBeFalse();
});
it('determines if GC is healthy', function () {
$healthy = new GcStatus(runs: 10, collected: 50, threshold: 10000, roots: 100);
$unhealthy = new GcStatus(runs: 0, collected: 0, threshold: 1000, roots: 950);
expect($healthy->isHealthy())->toBeTrue();
expect($unhealthy->isHealthy())->toBeFalse();
});
it('converts to array', function () {
$status = new GcStatus(runs: 10, collected: 50, threshold: 10001, roots: 100);
$array = $status->toArray();
expect($array)->toHaveKeys([
'runs',
'collected',
'threshold',
'roots',
'running',
'collection_efficiency',
'threshold_utilization',
'is_healthy',
]);
});
});
describe('GcResult', function () {
it('determines if GC was effective', function () {
$effective = new GcResult(
collected: 10,
duration: App\Framework\Core\ValueObjects\Duration::fromMilliseconds(5.0),
memoryFreed: App\Framework\Core\ValueObjects\Byte::fromBytes(1024),
statusBefore: new GcStatus(runs: 1, collected: 0, threshold: 10001, roots: 100),
statusAfter: new GcStatus(runs: 2, collected: 10, threshold: 10001, roots: 90),
timestamp: App\Framework\Core\ValueObjects\Timestamp::now()
);
$ineffective = new GcResult(
collected: 0,
duration: App\Framework\Core\ValueObjects\Duration::fromMilliseconds(5.0),
memoryFreed: App\Framework\Core\ValueObjects\Byte::fromBytes(0),
statusBefore: new GcStatus(runs: 1, collected: 0, threshold: 10001, roots: 100),
statusAfter: new GcStatus(runs: 2, collected: 0, threshold: 10001, roots: 100),
timestamp: App\Framework\Core\ValueObjects\Timestamp::now()
);
expect($effective->wasEffective())->toBeTrue();
expect($ineffective->wasEffective())->toBeFalse();
});
it('gets GC overhead in milliseconds', function () {
$result = new GcResult(
collected: 5,
duration: App\Framework\Core\ValueObjects\Duration::fromMilliseconds(12.5),
memoryFreed: App\Framework\Core\ValueObjects\Byte::fromBytes(2048),
statusBefore: new GcStatus(runs: 1, collected: 0, threshold: 10001, roots: 100),
statusAfter: new GcStatus(runs: 2, collected: 5, threshold: 10001, roots: 95),
timestamp: App\Framework\Core\ValueObjects\Timestamp::now()
);
expect($result->getOverheadMs())->toBeFloat();
expect($result->getOverheadMs())->toBeGreaterThan(0);
});
it('gets memory freed in megabytes', function () {
$result = new GcResult(
collected: 5,
duration: App\Framework\Core\ValueObjects\Duration::fromMilliseconds(5.0),
memoryFreed: App\Framework\Core\ValueObjects\Byte::fromBytes(1048576), // 1 MB
statusBefore: new GcStatus(runs: 1, collected: 0, threshold: 10001, roots: 100),
statusAfter: new GcStatus(runs: 2, collected: 5, threshold: 10001, roots: 95),
timestamp: App\Framework\Core\ValueObjects\Timestamp::now()
);
expect($result->getMemoryFreedMB())->toBe(1.0);
});
it('calculates efficiency score', function () {
$result = new GcResult(
collected: 5,
duration: App\Framework\Core\ValueObjects\Duration::fromMilliseconds(5.0),
memoryFreed: App\Framework\Core\ValueObjects\Byte::fromBytes(1048576),
statusBefore: new GcStatus(runs: 1, collected: 0, threshold: 10001, roots: 100),
statusAfter: new GcStatus(runs: 2, collected: 5, threshold: 10001, roots: 95),
timestamp: App\Framework\Core\ValueObjects\Timestamp::now()
);
$score = $result->getEfficiencyScore();
expect($score)->toBeFloat();
expect($score)->toBeGreaterThanOrEqual(0);
expect($score)->toBeLessThanOrEqual(100);
});
it('gets status changes', function () {
$result = new GcResult(
collected: 5,
duration: App\Framework\Core\ValueObjects\Duration::fromMilliseconds(5.0),
memoryFreed: App\Framework\Core\ValueObjects\Byte::fromBytes(1024),
statusBefore: new GcStatus(runs: 1, collected: 10, threshold: 10001, roots: 100),
statusAfter: new GcStatus(runs: 2, collected: 15, threshold: 10001, roots: 95),
timestamp: App\Framework\Core\ValueObjects\Timestamp::now()
);
$changes = $result->getStatusChanges();
expect($changes)->toHaveKeys(['runs_delta', 'collected_delta', 'roots_delta']);
expect($changes['runs_delta'])->toBe(1);
expect($changes['collected_delta'])->toBe(5);
expect($changes['roots_delta'])->toBe(-5);
});
it('converts to array', function () {
$result = new GcResult(
collected: 5,
duration: App\Framework\Core\ValueObjects\Duration::fromMilliseconds(5.0),
memoryFreed: App\Framework\Core\ValueObjects\Byte::fromBytes(1024),
statusBefore: new GcStatus(runs: 1, collected: 0, threshold: 10001, roots: 100),
statusAfter: new GcStatus(runs: 2, collected: 5, threshold: 10001, roots: 95),
timestamp: App\Framework\Core\ValueObjects\Timestamp::now()
);
$array = $result->toArray();
expect($array)->toHaveKeys([
'collected',
'duration_ms',
'memory_freed_bytes',
'memory_freed_mb',
'timestamp',
'was_effective',
'efficiency_score',
'status_before',
'status_after',
'status_changes',
]);
});
});