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

@@ -14,7 +14,9 @@ use PHPUnit\Framework\TestCase;
final class DatabasePerformanceTest extends TestCase
{
private DatabaseManager $database;
private WorkerRegistry $workerRegistry;
private JobDistributionService $distributionService;
protected function setUp(): void
@@ -55,7 +57,7 @@ final class DatabasePerformanceTest extends TestCase
$randomWorker = $workers[array_rand($workers)];
$workerId = $randomWorker->id->toString();
$time = PerformanceTestHelper::measureTime(function() use ($workerId) {
$time = PerformanceTestHelper::measureTime(function () use ($workerId) {
return $this->workerRegistry->getWorker($workerId);
});
@@ -68,7 +70,7 @@ final class DatabasePerformanceTest extends TestCase
// Test getting available workers
$availableWorkerTimes = [];
for ($i = 0; $i < 100; $i++) {
$time = PerformanceTestHelper::measureTime(function() {
$time = PerformanceTestHelper::measureTime(function () {
return $this->workerRegistry->getAvailableWorkers();
});
$availableWorkerTimes[] = $time;
@@ -83,7 +85,7 @@ final class DatabasePerformanceTest extends TestCase
$randomWorker = $workers[array_rand($workers)];
$workerId = $randomWorker->id->toString();
$time = PerformanceTestHelper::measureTime(function() use ($workerId) {
$time = PerformanceTestHelper::measureTime(function () use ($workerId) {
$this->updateWorkerStatus($workerId, WorkerStatus::BUSY);
$this->updateWorkerStatus($workerId, WorkerStatus::AVAILABLE);
});
@@ -136,7 +138,7 @@ final class DatabasePerformanceTest extends TestCase
$randomJob = $jobs[array_rand($jobs)];
$jobId = $randomJob->id;
$time = PerformanceTestHelper::measureTime(function() use ($jobId) {
$time = PerformanceTestHelper::measureTime(function () use ($jobId) {
return $this->getJobById($jobId);
});
@@ -152,7 +154,7 @@ final class DatabasePerformanceTest extends TestCase
foreach ($statuses as $status) {
for ($i = 0; $i < 25; $i++) {
$time = PerformanceTestHelper::measureTime(function() use ($status) {
$time = PerformanceTestHelper::measureTime(function () use ($status) {
return $this->getJobsByStatus($status);
});
$statusQueryTimes[] = $time;
@@ -168,7 +170,7 @@ final class DatabasePerformanceTest extends TestCase
$randomWorker = $workers[array_rand($workers)];
$workerId = $randomWorker->id->toString();
$time = PerformanceTestHelper::measureTime(function() use ($workerId) {
$time = PerformanceTestHelper::measureTime(function () use ($workerId) {
return $this->getJobsByWorker($workerId);
});
@@ -199,21 +201,21 @@ final class DatabasePerformanceTest extends TestCase
// Test batch worker registration
$workers = $this->createWorkers($batchSize, 20);
$batchRegisterTime = PerformanceTestHelper::measureTime(function() use ($workers) {
$batchRegisterTime = PerformanceTestHelper::measureTime(function () use ($workers) {
$this->registerWorkers($workers);
});
// Test batch job distribution
$jobs = PerformanceTestHelper::createBulkJobs($batchSize);
$batchDistributeTime = PerformanceTestHelper::measureTime(function() use ($jobs) {
$batchDistributeTime = PerformanceTestHelper::measureTime(function () use ($jobs) {
foreach ($jobs as $job) {
$this->distributionService->distributeJob($job);
}
});
// Test batch job status updates
$batchUpdateTime = PerformanceTestHelper::measureTime(function() use ($jobs) {
$batchUpdateTime = PerformanceTestHelper::measureTime(function () use ($jobs) {
foreach ($jobs as $job) {
$this->updateJobStatus($job->id, JobStatus::COMPLETED);
}
@@ -262,22 +264,23 @@ final class DatabasePerformanceTest extends TestCase
// Test indexed queries performance
$indexTests = [
'worker_by_id' => function() use ($workers) {
'worker_by_id' => function () use ($workers) {
$randomWorker = $workers[array_rand($workers)];
return $this->workerRegistry->getWorker($randomWorker->id->toString());
},
'workers_by_status' => function() {
'workers_by_status' => function () {
return $this->workerRegistry->getWorkersByStatus(WorkerStatus::AVAILABLE);
},
'jobs_by_status' => function() {
'jobs_by_status' => function () {
return $this->getJobsByStatus(JobStatus::PENDING);
},
'jobs_by_priority' => function() {
'jobs_by_priority' => function () {
return $this->getJobsByPriority(\App\Framework\Queue\Jobs\JobPriority::HIGH);
},
'jobs_by_queue' => function() {
'jobs_by_queue' => function () {
return $this->getJobsByQueue('test_queue');
}
},
];
foreach ($indexTests as $testName => $testFunction) {
@@ -303,17 +306,19 @@ final class DatabasePerformanceTest extends TestCase
// Simulate multiple concurrent database operations
$operationTypes = [
'worker_lookup' => function() {
'worker_lookup' => function () {
$workerId = 'worker_' . rand(1, 100);
return $this->workerRegistry->getWorker($workerId);
},
'job_insertion' => function() {
'job_insertion' => function () {
$job = PerformanceTestHelper::createTestJob('pool_test_' . uniqid());
return $this->distributionService->distributeJob($job);
},
'status_query' => function() {
'status_query' => function () {
return $this->getJobsByStatus(JobStatus::PENDING);
}
},
];
$concurrencyLevels = [1, 5, 10, 20];
@@ -361,18 +366,18 @@ final class DatabasePerformanceTest extends TestCase
// Test complex queries that should benefit from optimization
$complexQueries = [
'workers_with_capacity_filter' => function() {
'workers_with_capacity_filter' => function () {
return $this->getWorkersByCapacityRange(15, 25);
},
'jobs_with_multiple_filters' => function() {
'jobs_with_multiple_filters' => function () {
return $this->getJobsWithFilters(JobStatus::PENDING, \App\Framework\Queue\Jobs\JobPriority::NORMAL);
},
'job_count_aggregation' => function() {
'job_count_aggregation' => function () {
return $this->getJobCountsByStatus();
},
'worker_utilization_stats' => function() {
'worker_utilization_stats' => function () {
return $this->getWorkerUtilizationStats();
}
},
];
foreach ($complexQueries as $queryName => $queryFunction) {
@@ -406,7 +411,7 @@ final class DatabasePerformanceTest extends TestCase
$transactionTimes = [];
for ($iteration = 0; $iteration < 20; $iteration++) {
$time = PerformanceTestHelper::measureTime(function() use ($size, $iteration) {
$time = PerformanceTestHelper::measureTime(function () use ($size, $iteration) {
$pdo = $this->database->getConnection();
try {
@@ -420,6 +425,7 @@ final class DatabasePerformanceTest extends TestCase
$pdo->commit();
} catch (\Exception $e) {
$pdo->rollBack();
throw $e;
}
});
@@ -454,6 +460,7 @@ final class DatabasePerformanceTest extends TestCase
$status
);
}
return $workers;
}
@@ -483,6 +490,7 @@ final class DatabasePerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE id = ?');
$stmt->execute([$jobId]);
return $stmt->fetch(\PDO::FETCH_ASSOC) ?: null;
}
@@ -491,6 +499,7 @@ final class DatabasePerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE status = ? LIMIT 100');
$stmt->execute([$status->value]);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
@@ -499,6 +508,7 @@ final class DatabasePerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE worker_id = ? LIMIT 100');
$stmt->execute([$workerId]);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
@@ -507,6 +517,7 @@ final class DatabasePerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE priority = ? LIMIT 100');
$stmt->execute([$priority->value]);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
@@ -515,6 +526,7 @@ final class DatabasePerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE queue_name = ? LIMIT 100');
$stmt->execute([$queueName]);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
@@ -523,6 +535,7 @@ final class DatabasePerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT * FROM workers WHERE capacity BETWEEN ? AND ?');
$stmt->execute([$minCapacity, $maxCapacity]);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
@@ -531,6 +544,7 @@ final class DatabasePerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE status = ? AND priority = ? LIMIT 100');
$stmt->execute([$status->value, $priority->value]);
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
@@ -538,6 +552,7 @@ final class DatabasePerformanceTest extends TestCase
{
$pdo = $this->database->getConnection();
$stmt = $pdo->query('SELECT status, COUNT(*) as count FROM jobs GROUP BY status');
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
@@ -554,6 +569,7 @@ final class DatabasePerformanceTest extends TestCase
LEFT JOIN jobs j ON w.id = j.worker_id
GROUP BY w.status
');
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
}
@@ -619,4 +635,4 @@ final class DatabasePerformanceTest extends TestCase
$pdo->exec('DELETE FROM workers');
$pdo->exec('DELETE FROM jobs');
}
}
}

View File

@@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase;
final class DistributedLockPerformanceTest extends TestCase
{
private DatabaseManager $database;
private DatabaseDistributedLock $lockService;
protected function setUp(): void
@@ -38,11 +39,12 @@ final class DistributedLockPerformanceTest extends TestCase
$lockKey = new LockKey("test_lock_{$i}");
$owner = new LockOwner("owner_{$i}");
$time = PerformanceTestHelper::measureTime(function() use ($lockKey, $owner) {
$time = PerformanceTestHelper::measureTime(function () use ($lockKey, $owner) {
$acquired = $this->lockService->acquire($lockKey, $owner, 30);
if ($acquired) {
$this->lockService->release($lockKey, $owner);
}
return $acquired;
});
@@ -87,7 +89,7 @@ final class DistributedLockPerformanceTest extends TestCase
// Measure release times
foreach ($locks as $lock) {
$time = PerformanceTestHelper::measureTime(function() use ($lock) {
$time = PerformanceTestHelper::measureTime(function () use ($lock) {
return $this->lockService->release($lock['key'], $lock['owner']);
});
$releaseTimes[] = $time;
@@ -130,14 +132,16 @@ final class DistributedLockPerformanceTest extends TestCase
$failures = 0;
for ($attempt = 0; $attempt < $attemptsPerWorker; $attempt++) {
$result = PerformanceTestHelper::measureTimeWithResult(function() use ($lockKey, $owner) {
$result = PerformanceTestHelper::measureTimeWithResult(function () use ($lockKey, $owner) {
$acquired = $this->lockService->acquire($lockKey, $owner, 1); // 1 second timeout
if ($acquired) {
// Hold lock briefly then release
usleep(100); // 0.1ms
$this->lockService->release($lockKey, $owner);
return true;
}
return false;
});
@@ -194,7 +198,7 @@ final class DistributedLockPerformanceTest extends TestCase
// Second owner repeatedly tries to acquire with short timeouts
for ($i = 0; $i < $iterations; $i++) {
$result = PerformanceTestHelper::measureTimeWithResult(function() use ($lockKey, $owner2) {
$result = PerformanceTestHelper::measureTimeWithResult(function () use ($lockKey, $owner2) {
return $this->lockService->acquire($lockKey, $owner2, 0.1); // 100ms timeout
});
@@ -251,7 +255,7 @@ final class DistributedLockPerformanceTest extends TestCase
}
// Measure cleanup performance
$cleanupTime = PerformanceTestHelper::measureTime(function() {
$cleanupTime = PerformanceTestHelper::measureTime(function () {
$this->lockService->cleanupExpiredLocks();
});
@@ -282,7 +286,7 @@ final class DistributedLockPerformanceTest extends TestCase
));
}
$largeCleanupTime = PerformanceTestHelper::measureTime(function() {
$largeCleanupTime = PerformanceTestHelper::measureTime(function () {
$this->lockService->cleanupExpiredLocks();
});
@@ -301,7 +305,7 @@ final class DistributedLockPerformanceTest extends TestCase
echo "Target: {$operationsPerSecond} operations/second for {$testDuration} seconds\n";
$loadResult = PerformanceTestHelper::simulateLoad(
function($index) {
function ($index) {
$lockKey = new LockKey("throughput_lock_{$index}");
$owner = new LockOwner("owner_{$index}");
@@ -309,8 +313,10 @@ final class DistributedLockPerformanceTest extends TestCase
$acquired = $this->lockService->acquire($lockKey, $owner, 5);
if ($acquired) {
$this->lockService->release($lockKey, $owner);
return true;
}
return false;
},
$totalOperations,
@@ -324,7 +330,7 @@ final class DistributedLockPerformanceTest extends TestCase
$successfulOperations = count(array_filter(
array_column($loadResult['results'], 'result'),
fn($result) => $result['result'] === true
fn ($result) => $result['result'] === true
));
echo "Actual Throughput: {$actualThroughput} operations/second\n";
@@ -371,18 +377,19 @@ final class DistributedLockPerformanceTest extends TestCase
$this->lockService->release($lockKey, $owner1);
}
$result = PerformanceTestHelper::measureTimeWithResult(function() use ($lockKey, $owner2) {
$result = PerformanceTestHelper::measureTimeWithResult(function () use ($lockKey, $owner2) {
return $this->lockService->acquire($lockKey, $owner2, 0.01); // 10ms timeout
});
$retryAttempts[] = [
'time_ms' => $result['time_ms'],
'success' => $result['result']
'success' => $result['result'],
];
if ($result['result']) {
// Successfully acquired, release it and stop
$this->lockService->release($lockKey, $owner2);
break;
}
@@ -432,4 +439,4 @@ final class DistributedLockPerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$pdo->exec('DELETE FROM distributed_locks');
}
}
}

View File

@@ -16,9 +16,13 @@ use PHPUnit\Framework\TestCase;
final class FailoverPerformanceTest extends TestCase
{
private DatabaseManager $database;
private WorkerRegistry $workerRegistry;
private WorkerHealthCheckService $healthCheckService;
private FailoverRecoveryService $failoverService;
private JobDistributionService $distributionService;
protected function setUp(): void
@@ -70,7 +74,7 @@ final class FailoverPerformanceTest extends TestCase
$iterations = 10;
for ($i = 0; $i < $iterations; $i++) {
$time = PerformanceTestHelper::measureTime(function() {
$time = PerformanceTestHelper::measureTime(function () {
return $this->healthCheckService->checkAllWorkers();
});
$detectionTimes[] = $time;
@@ -83,7 +87,7 @@ final class FailoverPerformanceTest extends TestCase
// Verify failed workers were detected
$failedWorkers = $this->workerRegistry->getWorkersByStatus(WorkerStatus::FAILED);
$detectedFailures = array_map(fn($w) => $w->id->toString(), $failedWorkers);
$detectedFailures = array_map(fn ($w) => $w->id->toString(), $failedWorkers);
echo "\nWorker Failure Detection Results:\n";
echo "Workers created: " . count($workers) . "\n";
@@ -123,7 +127,7 @@ final class FailoverPerformanceTest extends TestCase
if ($assignedWorker) {
$assignedJobs[] = [
'job' => $job,
'worker_id' => $assignedWorker->id->toString()
'worker_id' => $assignedWorker->id->toString(),
];
}
}
@@ -135,7 +139,7 @@ final class FailoverPerformanceTest extends TestCase
// Find jobs assigned to failed worker
$jobsToReassign = array_filter(
$assignedJobs,
fn($item) => $item['worker_id'] === $failedWorkerId
fn ($item) => $item['worker_id'] === $failedWorkerId
);
echo "\nJob Reassignment Test:\n";
@@ -143,7 +147,7 @@ final class FailoverPerformanceTest extends TestCase
echo "Jobs to reassign: " . count($jobsToReassign) . "\n";
// Measure job reassignment performance
$reassignmentTime = PerformanceTestHelper::measureTime(function() use ($failedWorkerId) {
$reassignmentTime = PerformanceTestHelper::measureTime(function () use ($failedWorkerId) {
return $this->failoverService->reassignFailedWorkerJobs($failedWorkerId);
});
@@ -184,7 +188,7 @@ final class FailoverPerformanceTest extends TestCase
$failedWorkerIds = [
$workers[0]->id->toString(),
$workers[1]->id->toString(),
$workers[2]->id->toString()
$workers[2]->id->toString(),
];
foreach ($failedWorkerIds as $workerId) {
@@ -197,7 +201,7 @@ final class FailoverPerformanceTest extends TestCase
echo "Total jobs: " . count($jobs) . "\n";
// Measure full system recovery time
$recoveryTime = PerformanceTestHelper::measureTime(function() {
$recoveryTime = PerformanceTestHelper::measureTime(function () {
return $this->failoverService->performFullSystemRecovery();
});
@@ -231,7 +235,7 @@ final class FailoverPerformanceTest extends TestCase
PerformanceTestHelper::createTestWorker('medium_capacity_1', 20),
PerformanceTestHelper::createTestWorker('medium_capacity_2', 20),
PerformanceTestHelper::createTestWorker('low_capacity_1', 10),
PerformanceTestHelper::createTestWorker('low_capacity_2', 10)
PerformanceTestHelper::createTestWorker('low_capacity_2', 10),
];
$this->registerWorkers($workers);
@@ -289,7 +293,7 @@ final class FailoverPerformanceTest extends TestCase
while (microtime(true) < $endTime) {
$job = PerformanceTestHelper::createTestJob("load_job_{$jobsDistributed}");
$result = PerformanceTestHelper::measureTimeWithResult(function() use ($job) {
$result = PerformanceTestHelper::measureTimeWithResult(function () use ($job) {
try {
return $this->distributionService->distributeJob($job);
} catch (\Exception $e) {
@@ -352,7 +356,7 @@ final class FailoverPerformanceTest extends TestCase
$failedWorkerIds = [
$workers[0]->id->toString(),
$workers[1]->id->toString(),
$workers[2]->id->toString()
$workers[2]->id->toString(),
];
foreach ($failedWorkerIds as $workerId) {
@@ -369,7 +373,7 @@ final class FailoverPerformanceTest extends TestCase
// Update heartbeat to simulate worker recovery
$this->updateWorkerHeartbeat($workerId, new \DateTimeImmutable());
$recoveryTime = PerformanceTestHelper::measureTime(function() use ($workerId) {
$recoveryTime = PerformanceTestHelper::measureTime(function () use ($workerId) {
// Simulate health check detecting recovery
$this->healthCheckService->checkWorker($workerId);
@@ -434,6 +438,7 @@ final class FailoverPerformanceTest extends TestCase
WorkerStatus::AVAILABLE
);
}
return $workers;
}
@@ -463,6 +468,7 @@ final class FailoverPerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT COUNT(*) FROM jobs WHERE worker_id != ? AND worker_id IS NOT NULL');
$stmt->execute([$failedWorkerId]);
return (int) $stmt->fetchColumn();
}
@@ -471,6 +477,7 @@ final class FailoverPerformanceTest extends TestCase
$pdo = $this->database->getConnection();
$stmt = $pdo->prepare('SELECT COUNT(*) FROM jobs WHERE status = ?');
$stmt->execute([$status->value]);
return (int) $stmt->fetchColumn();
}
@@ -521,4 +528,4 @@ final class FailoverPerformanceTest extends TestCase
$pdo->exec('DELETE FROM workers');
$pdo->exec('DELETE FROM jobs');
}
}
}

View File

@@ -16,8 +16,11 @@ use PHPUnit\Framework\TestCase;
final class LoadBalancingPerformanceTest extends TestCase
{
private DatabaseManager $database;
private WorkerRegistry $workerRegistry;
private JobDistributionService $distributionService;
private LoadBalancer $loadBalancer;
protected function setUp(): void
@@ -47,7 +50,7 @@ final class LoadBalancingPerformanceTest extends TestCase
PerformanceTestHelper::createTestWorker('worker_2', 15),
PerformanceTestHelper::createTestWorker('worker_3', 10),
PerformanceTestHelper::createTestWorker('worker_4', 25),
PerformanceTestHelper::createTestWorker('worker_5', 30)
PerformanceTestHelper::createTestWorker('worker_5', 30),
];
$this->registerWorkers($workers);
@@ -56,7 +59,7 @@ final class LoadBalancingPerformanceTest extends TestCase
$iterations = 1000;
for ($i = 0; $i < $iterations; $i++) {
$time = PerformanceTestHelper::measureTime(function() {
$time = PerformanceTestHelper::measureTime(function () {
$this->loadBalancer->selectWorker(new QueueName('test_queue'));
});
$selectionTimes[] = $time;
@@ -92,7 +95,7 @@ final class LoadBalancingPerformanceTest extends TestCase
for ($i = 0; $i < $iterations; $i++) {
$job = PerformanceTestHelper::createTestJob("dist_job_{$i}");
$time = PerformanceTestHelper::measureTime(function() use ($job) {
$time = PerformanceTestHelper::measureTime(function () use ($job) {
$this->distributionService->distributeJob($job);
});
@@ -131,8 +134,9 @@ final class LoadBalancingPerformanceTest extends TestCase
echo "Target: {$jobsPerSecond} jobs/second for {$testDuration} seconds\n";
$loadResult = PerformanceTestHelper::simulateLoad(
function($index) {
function ($index) {
$job = PerformanceTestHelper::createTestJob("load_job_{$index}");
return $this->distributionService->distributeJob($job);
},
$totalJobs,
@@ -166,7 +170,7 @@ final class LoadBalancingPerformanceTest extends TestCase
PerformanceTestHelper::createTestWorker('worker_2', 20),
PerformanceTestHelper::createTestWorker('worker_3', 30),
PerformanceTestHelper::createTestWorker('worker_4', 15),
PerformanceTestHelper::createTestWorker('worker_5', 25)
PerformanceTestHelper::createTestWorker('worker_5', 25),
];
$this->registerWorkers($workers);
@@ -185,7 +189,7 @@ final class LoadBalancingPerformanceTest extends TestCase
}
echo "\nFair Distribution Results:\n";
$totalCapacity = array_sum(array_map(fn($w) => $w->capacity->value, $workers));
$totalCapacity = array_sum(array_map(fn ($w) => $w->capacity->value, $workers));
foreach ($workers as $worker) {
$workerId = $worker->id->toString();
@@ -228,7 +232,7 @@ final class LoadBalancingPerformanceTest extends TestCase
PerformanceTestHelper::createTestWorker('medium_worker_1', 15),
PerformanceTestHelper::createTestWorker('medium_worker_2', 20),
PerformanceTestHelper::createTestWorker('large_worker', 50),
PerformanceTestHelper::createTestWorker('xlarge_worker', 100)
PerformanceTestHelper::createTestWorker('xlarge_worker', 100),
];
$this->registerWorkers($workers);
@@ -237,7 +241,7 @@ final class LoadBalancingPerformanceTest extends TestCase
$iterations = 500;
for ($i = 0; $i < $iterations; $i++) {
$time = PerformanceTestHelper::measureTime(function() {
$time = PerformanceTestHelper::measureTime(function () {
$this->loadBalancer->selectWorker(new QueueName('test_queue'));
});
$selectionTimes[] = $time;
@@ -271,7 +275,7 @@ final class LoadBalancingPerformanceTest extends TestCase
$priority
);
$time = PerformanceTestHelper::measureTime(function() use ($job) {
$time = PerformanceTestHelper::measureTime(function () use ($job) {
$this->distributionService->distributeJob($job);
});
@@ -296,7 +300,7 @@ final class LoadBalancingPerformanceTest extends TestCase
$workers = [
PerformanceTestHelper::createTestWorker('worker_1', 2),
PerformanceTestHelper::createTestWorker('worker_2', 3),
PerformanceTestHelper::createTestWorker('worker_3', 2)
PerformanceTestHelper::createTestWorker('worker_3', 2),
];
$this->registerWorkers($workers);
@@ -311,7 +315,7 @@ final class LoadBalancingPerformanceTest extends TestCase
for ($i = 0; $i < $jobCount; $i++) {
$job = PerformanceTestHelper::createTestJob("overload_job_{$i}");
$result = PerformanceTestHelper::measureTimeWithResult(function() use ($job) {
$result = PerformanceTestHelper::measureTimeWithResult(function () use ($job) {
return $this->distributionService->distributeJob($job);
});
@@ -349,6 +353,7 @@ final class LoadBalancingPerformanceTest extends TestCase
WorkerStatus::AVAILABLE
);
}
return $workers;
}
@@ -408,4 +413,4 @@ final class LoadBalancingPerformanceTest extends TestCase
$pdo->exec('DELETE FROM workers');
$pdo->exec('DELETE FROM jobs');
}
}
}

View File

@@ -6,13 +6,7 @@ namespace Tests\Framework\Queue\Performance;
use App\Framework\Database\DatabaseManager;
use App\Framework\Queue\Distribution\JobDistributionService;
use App\Framework\Queue\Jobs\Job;
use App\Framework\Queue\Jobs\JobPriority;
use App\Framework\Queue\Jobs\JobStatus;
use App\Framework\Queue\Queue\QueueName;
use App\Framework\Queue\Workers\Worker;
use App\Framework\Queue\Workers\WorkerCapacity;
use App\Framework\Queue\Workers\WorkerId;
use App\Framework\Queue\Workers\WorkerRegistry;
use App\Framework\Queue\Workers\WorkerStatus;
use PHPUnit\Framework\TestCase;
@@ -20,7 +14,9 @@ use PHPUnit\Framework\TestCase;
final class MultiWorkerThroughputTest extends TestCase
{
private DatabaseManager $database;
private WorkerRegistry $workerRegistry;
private JobDistributionService $distributionService;
protected function setUp(): void
@@ -134,7 +130,7 @@ final class MultiWorkerThroughputTest extends TestCase
['workers' => 1, 'jobs' => 50, 'capacity' => 50],
['workers' => 5, 'jobs' => 250, 'capacity' => 20],
['workers' => 10, 'jobs' => 500, 'capacity' => 15],
['workers' => 20, 'jobs' => 1000, 'capacity' => 10]
['workers' => 20, 'jobs' => 1000, 'capacity' => 10],
];
$results = [];
@@ -146,7 +142,7 @@ final class MultiWorkerThroughputTest extends TestCase
$results[] = [
'worker_count' => $case['workers'],
'throughput' => $result['throughput'],
'efficiency' => $result['throughput'] / $case['workers'] // Jobs per worker per second
'efficiency' => $result['throughput'] / $case['workers'], // Jobs per worker per second
];
$this->cleanupJobs();
@@ -190,7 +186,7 @@ final class MultiWorkerThroughputTest extends TestCase
PerformanceTestHelper::createTestWorker('worker_2', 30),
PerformanceTestHelper::createTestWorker('worker_3', 20),
PerformanceTestHelper::createTestWorker('worker_4', 10),
PerformanceTestHelper::createTestWorker('worker_5', 5)
PerformanceTestHelper::createTestWorker('worker_5', 5),
];
$this->registerWorkers($workers);
@@ -229,7 +225,7 @@ final class MultiWorkerThroughputTest extends TestCase
$batchStartTime = microtime(true);
foreach ($jobs as $job) {
$measureResult = PerformanceTestHelper::measureTimeWithResult(
fn() => $this->distributionService->distributeJob($job)
fn () => $this->distributionService->distributeJob($job)
);
$distributionTimes[] = $measureResult['time_ms'];
}
@@ -279,7 +275,7 @@ final class MultiWorkerThroughputTest extends TestCase
foreach ($jobs as $job) {
$measureResult = PerformanceTestHelper::measureTimeWithResult(
fn() => $this->distributionService->distributeJob($job)
fn () => $this->distributionService->distributeJob($job)
);
$distributionTimes[] = $measureResult['time_ms'];
}
@@ -292,7 +288,7 @@ final class MultiWorkerThroughputTest extends TestCase
'throughput' => round($throughput, 1),
'total_time_ms' => round($totalTimeMs, 1),
'distribution_stats' => PerformanceTestHelper::calculateStatistics($distributionTimes),
'jobs_processed' => $jobCount
'jobs_processed' => $jobCount,
];
}
@@ -306,6 +302,7 @@ final class MultiWorkerThroughputTest extends TestCase
WorkerStatus::AVAILABLE
);
}
return $workers;
}
@@ -383,4 +380,4 @@ final class MultiWorkerThroughputTest extends TestCase
$pdo = $this->database->getConnection();
$pdo->exec('DELETE FROM jobs WHERE status IN ("COMPLETED", "FAILED")');
}
}
}

View File

@@ -6,14 +6,13 @@ namespace Tests\Framework\Queue\Performance;
use App\Framework\Queue\Jobs\Job;
use App\Framework\Queue\Jobs\JobRequest;
use App\Framework\Queue\Jobs\JobResult;
use App\Framework\Queue\Jobs\JobStatus;
use App\Framework\Queue\Queue\JobPriority;
use App\Framework\Queue\Queue\QueueName;
use App\Framework\Queue\Workers\Worker;
use App\Framework\Queue\Workers\WorkerCapacity;
use App\Framework\Queue\Workers\WorkerId;
use App\Framework\Queue\Workers\WorkerStatus;
use App\Framework\Queue\Queue\QueueName;
use App\Framework\Queue\Queue\JobPriority;
final readonly class PerformanceTestHelper
{
@@ -61,6 +60,7 @@ final readonly class PerformanceTestHelper
payload: ['batch_id' => $i, 'data' => str_repeat('x', 100)]
);
}
return $jobs;
}
@@ -81,7 +81,7 @@ final readonly class PerformanceTestHelper
return [
'result' => $result,
'time_ms' => ($end - $start) * 1000
'time_ms' => ($end - $start) * 1000,
];
}
@@ -96,7 +96,7 @@ final readonly class PerformanceTestHelper
'median' => 0,
'p95' => 0,
'p99' => 0,
'stddev' => 0
'stddev' => 0,
];
}
@@ -132,7 +132,7 @@ final readonly class PerformanceTestHelper
'median' => round($median, 3),
'p95' => round($p95, 3),
'p99' => round($p99, 3),
'stddev' => round($stddev, 3)
'stddev' => round($stddev, 3),
];
}
@@ -141,12 +141,18 @@ final readonly class PerformanceTestHelper
return sprintf(
"Count: %d, Min: %.3f%s, Max: %.3f%s, Avg: %.3f%s, P95: %.3f%s, P99: %.3f%s, StdDev: %.3f%s",
$stats['count'],
$stats['min'], $unit,
$stats['max'], $unit,
$stats['avg'], $unit,
$stats['p95'], $unit,
$stats['p99'], $unit,
$stats['stddev'], $unit
$stats['min'],
$unit,
$stats['max'],
$unit,
$stats['avg'],
$unit,
$stats['p95'],
$unit,
$stats['p99'],
$unit,
$stats['stddev'],
$unit
);
}
@@ -187,7 +193,7 @@ final readonly class PerformanceTestHelper
'current_mb' => round(memory_get_usage(true) / 1024 / 1024, 2),
'peak_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
'current_real_mb' => round(memory_get_usage(false) / 1024 / 1024, 2),
'peak_real_mb' => round(memory_get_peak_usage(false) / 1024 / 1024, 2)
'peak_real_mb' => round(memory_get_peak_usage(false) / 1024 / 1024, 2),
];
}
@@ -204,7 +210,7 @@ final readonly class PerformanceTestHelper
$operations = [];
for ($i = 0; $i < $concurrency; $i++) {
$operations[] = function() use ($operation, $i) {
$operations[] = function () use ($operation, $i) {
return $operation($i);
};
}
@@ -233,7 +239,7 @@ final readonly class PerformanceTestHelper
// Execute concurrent operations
for ($i = 0; $i < $batchSize; $i++) {
$result = self::measureTimeWithResult(function() use ($operation, $batch, $i) {
$result = self::measureTimeWithResult(function () use ($operation, $batch, $i) {
return $operation($batch * $concurrency + $i);
});
$batchResults[] = $result;
@@ -253,7 +259,7 @@ final readonly class PerformanceTestHelper
'results' => $results,
'operations_completed' => $operationsCompleted,
'duration_seconds' => microtime(true) - $startTime,
'throughput_ops_per_sec' => $operationsCompleted / (microtime(true) - $startTime)
'throughput_ops_per_sec' => $operationsCompleted / (microtime(true) - $startTime),
];
}
@@ -292,4 +298,4 @@ final readonly class PerformanceTestHelper
return $report;
}
}
}

View File

@@ -9,7 +9,6 @@ use App\Framework\Queue\Distribution\JobDistributionService;
use App\Framework\Queue\Failover\FailoverRecoveryService;
use App\Framework\Queue\Health\WorkerHealthCheckService;
use App\Framework\Queue\Jobs\JobPriority;
use App\Framework\Queue\Jobs\JobStatus;
use App\Framework\Queue\Workers\WorkerRegistry;
use App\Framework\Queue\Workers\WorkerStatus;
use PHPUnit\Framework\TestCase;
@@ -17,9 +16,13 @@ use PHPUnit\Framework\TestCase;
final class RealisticLoadScenariosTest extends TestCase
{
private DatabaseManager $database;
private WorkerRegistry $workerRegistry;
private JobDistributionService $distributionService;
private WorkerHealthCheckService $healthCheckService;
private FailoverRecoveryService $failoverService;
protected function setUp(): void
@@ -60,7 +63,7 @@ final class RealisticLoadScenariosTest extends TestCase
// Medium-capacity workers for inventory updates
...$this->createWorkers(12, 30, 'inventory_worker'),
// Lower-capacity workers for email notifications
...$this->createWorkers(20, 15, 'notification_worker')
...$this->createWorkers(20, 15, 'notification_worker'),
];
$this->registerWorkers($workers);
@@ -105,7 +108,7 @@ final class RealisticLoadScenariosTest extends TestCase
// Medium workers for image processing
...$this->createWorkers(8, 50, 'image_processor'),
// Light workers for metadata extraction
...$this->createWorkers(12, 25, 'metadata_worker')
...$this->createWorkers(12, 25, 'metadata_worker'),
];
$this->registerWorkers($workers);
@@ -150,7 +153,7 @@ final class RealisticLoadScenariosTest extends TestCase
// Fraud detection workers
...$this->createWorkers(10, 15, 'fraud_detector'),
// Settlement workers
...$this->createWorkers(5, 30, 'settlement_worker')
...$this->createWorkers(5, 30, 'settlement_worker'),
];
$this->registerWorkers($workers);
@@ -197,7 +200,7 @@ final class RealisticLoadScenariosTest extends TestCase
// Data validation workers
...$this->createWorkers(8, 75, 'validator'),
// Report generation workers
...$this->createWorkers(4, 150, 'report_generator')
...$this->createWorkers(4, 150, 'report_generator'),
];
$this->registerWorkers($workers);
@@ -244,7 +247,7 @@ final class RealisticLoadScenariosTest extends TestCase
// Heavy computation workers
...$this->createWorkers(5, 80, 'compute_worker'),
// Notification workers
...$this->createWorkers(20, 10, 'notification_worker')
...$this->createWorkers(20, 10, 'notification_worker'),
];
$this->registerWorkers($workers);
@@ -254,7 +257,7 @@ final class RealisticLoadScenariosTest extends TestCase
['duration' => 60, 'rate' => 20, 'mix' => 'normal'],
['duration' => 120, 'rate' => 50, 'mix' => 'peak'],
['duration' => 60, 'rate' => 15, 'mix' => 'background'],
['duration' => 90, 'rate' => 35, 'mix' => 'mixed']
['duration' => 90, 'rate' => 35, 'mix' => 'mixed'],
];
$overallResults = [];
@@ -293,7 +296,7 @@ final class RealisticLoadScenariosTest extends TestCase
$workers = [
...$this->createWorkers(12, 25, 'primary_worker'),
...$this->createWorkers(8, 30, 'secondary_worker'),
...$this->createWorkers(6, 20, 'backup_worker')
...$this->createWorkers(6, 20, 'backup_worker'),
];
$this->registerWorkers($workers);
@@ -312,7 +315,7 @@ final class RealisticLoadScenariosTest extends TestCase
'jobs_processed' => 0,
'jobs_failed' => 0,
'response_times' => [],
'failover_events' => []
'failover_events' => [],
];
$failoverTriggered = false;
@@ -321,7 +324,7 @@ final class RealisticLoadScenariosTest extends TestCase
$cycleStart = microtime(true);
// Trigger failover at 1/3 of test duration
if (!$failoverTriggered && (microtime(true) - $startTime) > ($testDuration / 3)) {
if (! $failoverTriggered && (microtime(true) - $startTime) > ($testDuration / 3)) {
echo "\nTriggering failover scenario...\n";
// Fail primary workers
@@ -329,13 +332,13 @@ final class RealisticLoadScenariosTest extends TestCase
$this->updateWorkerStatus("primary_worker_{$i}", WorkerStatus::FAILED);
}
$failoverTime = PerformanceTestHelper::measureTime(function() {
$failoverTime = PerformanceTestHelper::measureTime(function () {
$this->failoverService->performFullSystemRecovery();
});
$metrics['failover_events'][] = [
'time' => microtime(true) - $startTime,
'recovery_time' => $failoverTime
'recovery_time' => $failoverTime,
];
echo "Failover completed in {$failoverTime}ms\n";
@@ -346,7 +349,7 @@ final class RealisticLoadScenariosTest extends TestCase
for ($i = 0; $i < $baseJobRate; $i++) {
$job = PerformanceTestHelper::createTestJob("realworld_job_{$metrics['jobs_processed']}");
$result = PerformanceTestHelper::measureTimeWithResult(function() use ($job) {
$result = PerformanceTestHelper::measureTimeWithResult(function () use ($job) {
try {
return $this->distributionService->distributeJob($job);
} catch (\Exception $e) {
@@ -382,7 +385,7 @@ final class RealisticLoadScenariosTest extends TestCase
echo "Success rate: {$successRate}%\n";
echo "Response times: " . PerformanceTestHelper::formatStatistics($responseStats) . "\n";
if (!empty($metrics['failover_events'])) {
if (! empty($metrics['failover_events'])) {
echo "Failover recovery time: {$metrics['failover_events'][0]['recovery_time']}ms\n";
}
@@ -408,7 +411,7 @@ final class RealisticLoadScenariosTest extends TestCase
'response_times' => [],
'memory_snapshots' => [],
'start_memory' => null,
'end_memory' => null
'end_memory' => null,
];
if ($enableResourceMonitoring) {
@@ -426,7 +429,7 @@ final class RealisticLoadScenariosTest extends TestCase
$jobType = $this->selectJobType($jobMix);
$job = $this->createJobForType($jobType, $jobCounter);
$result = PerformanceTestHelper::measureTimeWithResult(function() use ($job) {
$result = PerformanceTestHelper::measureTimeWithResult(function () use ($job) {
try {
return $this->distributionService->distributeJob($job);
} catch (\Exception $e) {
@@ -448,7 +451,7 @@ final class RealisticLoadScenariosTest extends TestCase
if ($enableResourceMonitoring && microtime(true) >= $nextSnapshotTime) {
$metrics['memory_snapshots'][] = [
'time' => microtime(true) - $startTime,
'memory' => PerformanceTestHelper::getMemoryUsage()
'memory' => PerformanceTestHelper::getMemoryUsage(),
];
$nextSnapshotTime += $snapshotInterval;
}
@@ -488,7 +491,7 @@ final class RealisticLoadScenariosTest extends TestCase
'success_rate' => round($successRate, 2),
'avg_response_time' => $responseStats['avg'],
'p95_response_time' => $responseStats['p95'],
'p99_response_time' => $responseStats['p99']
'p99_response_time' => $responseStats['p99'],
];
if ($includeResourceMetrics && isset($metrics['start_memory'], $metrics['end_memory'])) {
@@ -513,7 +516,7 @@ final class RealisticLoadScenariosTest extends TestCase
'inventory_update' => 25,
'payment_processing' => 20,
'email_notification' => 10,
'user_analytics' => 5
'user_analytics' => 5,
];
}
@@ -523,7 +526,7 @@ final class RealisticLoadScenariosTest extends TestCase
'video_transcode' => 30,
'image_resize' => 40,
'thumbnail_generation' => 20,
'metadata_extraction' => 10
'metadata_extraction' => 10,
];
}
@@ -533,7 +536,7 @@ final class RealisticLoadScenariosTest extends TestCase
'payment_processing' => 50,
'fraud_detection' => 25,
'account_verification' => 15,
'transaction_logging' => 10
'transaction_logging' => 10,
];
}
@@ -543,7 +546,7 @@ final class RealisticLoadScenariosTest extends TestCase
'data_transformation' => 40,
'data_validation' => 30,
'report_generation' => 20,
'data_archival' => 10
'data_archival' => 10,
];
}
@@ -553,24 +556,24 @@ final class RealisticLoadScenariosTest extends TestCase
'normal' => [
'web_request' => 50,
'background_task' => 30,
'notification' => 20
'notification' => 20,
],
'peak' => [
'web_request' => 60,
'background_task' => 20,
'notification' => 15,
'compute_task' => 5
'compute_task' => 5,
],
'background' => [
'background_task' => 60,
'compute_task' => 30,
'notification' => 10
'notification' => 10,
],
'mixed' => [
'web_request' => 35,
'background_task' => 25,
'compute_task' => 25,
'notification' => 15
'notification' => 15,
],
default => ['web_request' => 100]
};
@@ -638,7 +641,8 @@ final class RealisticLoadScenariosTest extends TestCase
private function calculateStandardDeviation(array $values): float
{
$mean = array_sum($values) / count($values);
$sumSquaredDiffs = array_sum(array_map(fn($v) => pow($v - $mean, 2), $values));
$sumSquaredDiffs = array_sum(array_map(fn ($v) => pow($v - $mean, 2), $values));
return sqrt($sumSquaredDiffs / count($values));
}
@@ -652,6 +656,7 @@ final class RealisticLoadScenariosTest extends TestCase
WorkerStatus::AVAILABLE
);
}
return $workers;
}
@@ -717,4 +722,4 @@ final class RealisticLoadScenariosTest extends TestCase
$pdo->exec('DELETE FROM workers');
$pdo->exec('DELETE FROM jobs');
}
}
}

View File

@@ -6,14 +6,15 @@ namespace Tests\Framework\Queue\Performance;
use App\Framework\Database\DatabaseManager;
use App\Framework\Queue\Distribution\JobDistributionService;
use App\Framework\Queue\Jobs\JobPriority;
use App\Framework\Queue\Workers\WorkerRegistry;
use PHPUnit\Framework\TestCase;
final class SystemResourcesTest extends TestCase
{
private DatabaseManager $database;
private WorkerRegistry $workerRegistry;
private JobDistributionService $distributionService;
protected function setUp(): void
@@ -96,7 +97,7 @@ final class SystemResourcesTest extends TestCase
['batch_size' => 50, 'batches' => 10],
['batch_size' => 100, 'batches' => 10],
['batch_size' => 500, 'batches' => 5],
['batch_size' => 1000, 'batches' => 3]
['batch_size' => 1000, 'batches' => 3],
];
foreach ($testCases as $case) {
@@ -110,7 +111,7 @@ final class SystemResourcesTest extends TestCase
for ($batch = 0; $batch < $batchCount; $batch++) {
$jobs = PerformanceTestHelper::createBulkJobs($batchSize);
$batchTime = PerformanceTestHelper::measureTime(function() use ($jobs) {
$batchTime = PerformanceTestHelper::measureTime(function () use ($jobs) {
foreach ($jobs as $job) {
$this->distributionService->distributeJob($job);
}
@@ -168,7 +169,7 @@ final class SystemResourcesTest extends TestCase
for ($i = 0; $i < $iterations; $i++) {
$job = PerformanceTestHelper::createTestJob("gc_test_job_{$i}");
$operationTime = PerformanceTestHelper::measureTime(function() use ($job) {
$operationTime = PerformanceTestHelper::measureTime(function () use ($job) {
return $this->distributionService->distributeJob($job);
});
@@ -179,7 +180,7 @@ final class SystemResourcesTest extends TestCase
$gcStats[] = [
'operation' => $i,
'memory' => PerformanceTestHelper::getMemoryUsage(),
'gc_stats' => gc_status()
'gc_stats' => gc_status(),
];
}
}
@@ -305,7 +306,7 @@ final class SystemResourcesTest extends TestCase
$memorySnapshots[] = [
'time' => $elapsed,
'operations' => $operationCount,
'memory' => $memory
'memory' => $memory,
];
echo sprintf(
@@ -384,7 +385,7 @@ final class SystemResourcesTest extends TestCase
echo "Memory after distribution: {$afterDistribution['current_mb']}MB\n";
// Measure cleanup time
$cleanupTime = PerformanceTestHelper::measureTime(function() {
$cleanupTime = PerformanceTestHelper::measureTime(function () {
$this->cleanupCompletedJobs();
});
@@ -426,7 +427,7 @@ final class SystemResourcesTest extends TestCase
$distributionTimes = [];
foreach ($jobs as $job) {
$time = PerformanceTestHelper::measureTime(function() use ($job) {
$time = PerformanceTestHelper::measureTime(function () use ($job) {
return $this->distributionService->distributeJob($job);
});
$distributionTimes[] = $time;
@@ -487,7 +488,7 @@ final class SystemResourcesTest extends TestCase
for ($op = 0; $op < $operationsPerWorker; $op++) {
$job = PerformanceTestHelper::createTestJob("concurrent_job_{$worker}_{$op}");
$time = PerformanceTestHelper::measureTime(function() use ($job) {
$time = PerformanceTestHelper::measureTime(function () use ($job) {
return $this->distributionService->distributeJob($job);
});
@@ -501,7 +502,7 @@ final class SystemResourcesTest extends TestCase
return [
'times' => $times,
'total_operations' => $actualOperations,
'duration' => $endTime - $startTime
'duration' => $endTime - $startTime,
];
}
@@ -556,6 +557,7 @@ final class SystemResourcesTest extends TestCase
$capacity
);
}
return $workers;
}
@@ -614,4 +616,4 @@ final class SystemResourcesTest extends TestCase
$pdo->exec('DELETE FROM workers');
$pdo->exec('DELETE FROM jobs');
}
}
}