- 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.
639 lines
23 KiB
PHP
639 lines
23 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Framework\Queue\Performance;
|
|
|
|
use App\Framework\Database\DatabaseManager;
|
|
use App\Framework\Queue\Distribution\JobDistributionService;
|
|
use App\Framework\Queue\Jobs\JobStatus;
|
|
use App\Framework\Queue\Workers\WorkerRegistry;
|
|
use App\Framework\Queue\Workers\WorkerStatus;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class DatabasePerformanceTest extends TestCase
|
|
{
|
|
private DatabaseManager $database;
|
|
|
|
private WorkerRegistry $workerRegistry;
|
|
|
|
private JobDistributionService $distributionService;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->database = $this->createTestDatabase();
|
|
$this->workerRegistry = new WorkerRegistry($this->database);
|
|
$this->distributionService = new JobDistributionService(
|
|
$this->database,
|
|
$this->workerRegistry
|
|
);
|
|
|
|
$this->cleanupTestData();
|
|
PerformanceTestHelper::warmupDatabase($this->database->getConnection());
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
$this->cleanupTestData();
|
|
}
|
|
|
|
public function testWorkerQueryPerformance(): void
|
|
{
|
|
// Create workers with different statuses and capacities
|
|
$workers = array_merge(
|
|
$this->createWorkers(50, 20, WorkerStatus::AVAILABLE),
|
|
$this->createWorkers(20, 15, WorkerStatus::BUSY),
|
|
$this->createWorkers(10, 25, WorkerStatus::FAILED)
|
|
);
|
|
|
|
$this->registerWorkers($workers);
|
|
|
|
echo "\nWorker Query Performance Test:\n";
|
|
echo "Total workers: " . count($workers) . "\n";
|
|
|
|
// Test worker lookup by ID
|
|
$workerLookupTimes = [];
|
|
for ($i = 0; $i < 100; $i++) {
|
|
$randomWorker = $workers[array_rand($workers)];
|
|
$workerId = $randomWorker->id->toString();
|
|
|
|
$time = PerformanceTestHelper::measureTime(function () use ($workerId) {
|
|
return $this->workerRegistry->getWorker($workerId);
|
|
});
|
|
|
|
$workerLookupTimes[] = $time;
|
|
}
|
|
|
|
$lookupStats = PerformanceTestHelper::calculateStatistics($workerLookupTimes);
|
|
echo "Worker lookup by ID: " . PerformanceTestHelper::formatStatistics($lookupStats) . "\n";
|
|
|
|
// Test getting available workers
|
|
$availableWorkerTimes = [];
|
|
for ($i = 0; $i < 100; $i++) {
|
|
$time = PerformanceTestHelper::measureTime(function () {
|
|
return $this->workerRegistry->getAvailableWorkers();
|
|
});
|
|
$availableWorkerTimes[] = $time;
|
|
}
|
|
|
|
$availableStats = PerformanceTestHelper::calculateStatistics($availableWorkerTimes);
|
|
echo "Get available workers: " . PerformanceTestHelper::formatStatistics($availableStats) . "\n";
|
|
|
|
// Test worker status updates
|
|
$updateTimes = [];
|
|
for ($i = 0; $i < 100; $i++) {
|
|
$randomWorker = $workers[array_rand($workers)];
|
|
$workerId = $randomWorker->id->toString();
|
|
|
|
$time = PerformanceTestHelper::measureTime(function () use ($workerId) {
|
|
$this->updateWorkerStatus($workerId, WorkerStatus::BUSY);
|
|
$this->updateWorkerStatus($workerId, WorkerStatus::AVAILABLE);
|
|
});
|
|
|
|
$updateTimes[] = $time;
|
|
}
|
|
|
|
$updateStats = PerformanceTestHelper::calculateStatistics($updateTimes);
|
|
echo "Worker status updates: " . PerformanceTestHelper::formatStatistics($updateStats) . "\n";
|
|
|
|
// Validate performance benchmarks
|
|
$this->assertLessThan(1.0, $lookupStats['avg'], 'Worker lookup average time exceeds 1ms');
|
|
$this->assertLessThan(2.0, $availableStats['avg'], 'Available workers query average time exceeds 2ms');
|
|
$this->assertLessThan(5.0, $updateStats['avg'], 'Worker update average time exceeds 5ms');
|
|
|
|
PerformanceTestHelper::assertPerformance($workerLookupTimes, 1.0, 2.0, 'Worker lookup');
|
|
PerformanceTestHelper::assertPerformance($availableWorkerTimes, 2.0, 5.0, 'Available workers query');
|
|
}
|
|
|
|
public function testJobQueryPerformance(): void
|
|
{
|
|
$workers = $this->createWorkers(20, 25);
|
|
$this->registerWorkers($workers);
|
|
|
|
// Create jobs with different statuses and priorities
|
|
$jobs = array_merge(
|
|
PerformanceTestHelper::createBulkJobs(500),
|
|
PerformanceTestHelper::createBulkJobs(300, \App\Framework\Queue\Jobs\JobPriority::HIGH),
|
|
PerformanceTestHelper::createBulkJobs(200, \App\Framework\Queue\Jobs\JobPriority::CRITICAL)
|
|
);
|
|
|
|
// Distribute and update job statuses
|
|
foreach ($jobs as $index => $job) {
|
|
$this->distributionService->distributeJob($job);
|
|
|
|
// Simulate some completed jobs
|
|
if ($index % 3 === 0) {
|
|
$this->updateJobStatus($job->id, JobStatus::COMPLETED);
|
|
} elseif ($index % 5 === 0) {
|
|
$this->updateJobStatus($job->id, JobStatus::FAILED);
|
|
}
|
|
}
|
|
|
|
echo "\nJob Query Performance Test:\n";
|
|
echo "Total jobs: " . count($jobs) . "\n";
|
|
|
|
// Test job lookup by ID
|
|
$jobLookupTimes = [];
|
|
for ($i = 0; $i < 100; $i++) {
|
|
$randomJob = $jobs[array_rand($jobs)];
|
|
$jobId = $randomJob->id;
|
|
|
|
$time = PerformanceTestHelper::measureTime(function () use ($jobId) {
|
|
return $this->getJobById($jobId);
|
|
});
|
|
|
|
$jobLookupTimes[] = $time;
|
|
}
|
|
|
|
$lookupStats = PerformanceTestHelper::calculateStatistics($jobLookupTimes);
|
|
echo "Job lookup by ID: " . PerformanceTestHelper::formatStatistics($lookupStats) . "\n";
|
|
|
|
// Test getting jobs by status
|
|
$statusQueryTimes = [];
|
|
$statuses = [JobStatus::PENDING, JobStatus::PROCESSING, JobStatus::COMPLETED, JobStatus::FAILED];
|
|
|
|
foreach ($statuses as $status) {
|
|
for ($i = 0; $i < 25; $i++) {
|
|
$time = PerformanceTestHelper::measureTime(function () use ($status) {
|
|
return $this->getJobsByStatus($status);
|
|
});
|
|
$statusQueryTimes[] = $time;
|
|
}
|
|
}
|
|
|
|
$statusStats = PerformanceTestHelper::calculateStatistics($statusQueryTimes);
|
|
echo "Jobs by status query: " . PerformanceTestHelper::formatStatistics($statusStats) . "\n";
|
|
|
|
// Test getting jobs by worker
|
|
$workerJobTimes = [];
|
|
for ($i = 0; $i < 50; $i++) {
|
|
$randomWorker = $workers[array_rand($workers)];
|
|
$workerId = $randomWorker->id->toString();
|
|
|
|
$time = PerformanceTestHelper::measureTime(function () use ($workerId) {
|
|
return $this->getJobsByWorker($workerId);
|
|
});
|
|
|
|
$workerJobTimes[] = $time;
|
|
}
|
|
|
|
$workerJobStats = PerformanceTestHelper::calculateStatistics($workerJobTimes);
|
|
echo "Jobs by worker query: " . PerformanceTestHelper::formatStatistics($workerJobStats) . "\n";
|
|
|
|
// Validate performance benchmarks
|
|
$this->assertLessThan(1.0, $lookupStats['avg'], 'Job lookup average time exceeds 1ms');
|
|
$this->assertLessThan(5.0, $statusStats['avg'], 'Job status query average time exceeds 5ms');
|
|
$this->assertLessThan(3.0, $workerJobStats['avg'], 'Jobs by worker query average time exceeds 3ms');
|
|
|
|
PerformanceTestHelper::assertPerformance($jobLookupTimes, 1.0, 2.0, 'Job lookup');
|
|
PerformanceTestHelper::assertPerformance($statusQueryTimes, 5.0, 10.0, 'Job status queries');
|
|
}
|
|
|
|
public function testBatchOperationPerformance(): void
|
|
{
|
|
echo "\nBatch Operation Performance Test:\n";
|
|
|
|
$batchSizes = [10, 50, 100, 500, 1000];
|
|
|
|
foreach ($batchSizes as $batchSize) {
|
|
echo "Testing batch size: {$batchSize}\n";
|
|
|
|
// Test batch worker registration
|
|
$workers = $this->createWorkers($batchSize, 20);
|
|
|
|
$batchRegisterTime = PerformanceTestHelper::measureTime(function () use ($workers) {
|
|
$this->registerWorkers($workers);
|
|
});
|
|
|
|
// Test batch job distribution
|
|
$jobs = PerformanceTestHelper::createBulkJobs($batchSize);
|
|
|
|
$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) {
|
|
foreach ($jobs as $job) {
|
|
$this->updateJobStatus($job->id, JobStatus::COMPLETED);
|
|
}
|
|
});
|
|
|
|
$perItemRegister = $batchRegisterTime / $batchSize;
|
|
$perItemDistribute = $batchDistributeTime / $batchSize;
|
|
$perItemUpdate = $batchUpdateTime / $batchSize;
|
|
|
|
echo sprintf(
|
|
" Register: %6.1fms total (%4.2fms/item), Distribute: %6.1fms (%4.2fms/item), Update: %6.1fms (%4.2fms/item)\n",
|
|
$batchRegisterTime,
|
|
$perItemRegister,
|
|
$batchDistributeTime,
|
|
$perItemDistribute,
|
|
$batchUpdateTime,
|
|
$perItemUpdate
|
|
);
|
|
|
|
// Batch operations should be efficient
|
|
$this->assertLessThan(2.0, $perItemRegister, "Worker registration too slow for batch size {$batchSize}");
|
|
$this->assertLessThan(5.0, $perItemDistribute, "Job distribution too slow for batch size {$batchSize}");
|
|
$this->assertLessThan(1.0, $perItemUpdate, "Job update too slow for batch size {$batchSize}");
|
|
|
|
$this->cleanupTestData();
|
|
}
|
|
}
|
|
|
|
public function testIndexEfficiency(): void
|
|
{
|
|
echo "\nIndex Efficiency Test:\n";
|
|
|
|
// Create large dataset to test index effectiveness
|
|
$workerCount = 1000;
|
|
$jobCount = 5000;
|
|
|
|
$workers = $this->createWorkers($workerCount, 20);
|
|
$this->registerWorkers($workers);
|
|
|
|
$jobs = PerformanceTestHelper::createBulkJobs($jobCount);
|
|
foreach ($jobs as $job) {
|
|
$this->distributionService->distributeJob($job);
|
|
}
|
|
|
|
echo "Dataset: {$workerCount} workers, {$jobCount} jobs\n";
|
|
|
|
// Test indexed queries performance
|
|
$indexTests = [
|
|
'worker_by_id' => function () use ($workers) {
|
|
$randomWorker = $workers[array_rand($workers)];
|
|
|
|
return $this->workerRegistry->getWorker($randomWorker->id->toString());
|
|
},
|
|
'workers_by_status' => function () {
|
|
return $this->workerRegistry->getWorkersByStatus(WorkerStatus::AVAILABLE);
|
|
},
|
|
'jobs_by_status' => function () {
|
|
return $this->getJobsByStatus(JobStatus::PENDING);
|
|
},
|
|
'jobs_by_priority' => function () {
|
|
return $this->getJobsByPriority(\App\Framework\Queue\Jobs\JobPriority::HIGH);
|
|
},
|
|
'jobs_by_queue' => function () {
|
|
return $this->getJobsByQueue('test_queue');
|
|
},
|
|
];
|
|
|
|
foreach ($indexTests as $testName => $testFunction) {
|
|
$times = [];
|
|
|
|
for ($i = 0; $i < 100; $i++) {
|
|
$time = PerformanceTestHelper::measureTime($testFunction);
|
|
$times[] = $time;
|
|
}
|
|
|
|
$stats = PerformanceTestHelper::calculateStatistics($times);
|
|
echo "{$testName}: " . PerformanceTestHelper::formatStatistics($stats) . "\n";
|
|
|
|
// All indexed queries should be fast even with large dataset
|
|
$this->assertLessThan(10.0, $stats['avg'], "Index query {$testName} too slow with large dataset");
|
|
$this->assertLessThan(25.0, $stats['p95'], "Index query {$testName} P95 too slow with large dataset");
|
|
}
|
|
}
|
|
|
|
public function testConnectionPoolingPerformance(): void
|
|
{
|
|
echo "\nConnection Pooling Performance Test:\n";
|
|
|
|
// Simulate multiple concurrent database operations
|
|
$operationTypes = [
|
|
'worker_lookup' => function () {
|
|
$workerId = 'worker_' . rand(1, 100);
|
|
|
|
return $this->workerRegistry->getWorker($workerId);
|
|
},
|
|
'job_insertion' => function () {
|
|
$job = PerformanceTestHelper::createTestJob('pool_test_' . uniqid());
|
|
|
|
return $this->distributionService->distributeJob($job);
|
|
},
|
|
'status_query' => function () {
|
|
return $this->getJobsByStatus(JobStatus::PENDING);
|
|
},
|
|
];
|
|
|
|
$concurrencyLevels = [1, 5, 10, 20];
|
|
|
|
foreach ($concurrencyLevels as $concurrency) {
|
|
echo "Testing concurrency level: {$concurrency}\n";
|
|
|
|
$operationTimes = [];
|
|
$operationsPerType = 20;
|
|
|
|
foreach ($operationTypes as $typeName => $operation) {
|
|
$typeTimes = [];
|
|
|
|
// Simulate concurrent operations (simplified for single-threaded PHP)
|
|
for ($i = 0; $i < $operationsPerType * $concurrency; $i++) {
|
|
$time = PerformanceTestHelper::measureTime($operation);
|
|
$typeTimes[] = $time;
|
|
$operationTimes[] = $time;
|
|
}
|
|
|
|
$typeStats = PerformanceTestHelper::calculateStatistics($typeTimes);
|
|
echo " {$typeName}: " . PerformanceTestHelper::formatStatistics($typeStats) . "\n";
|
|
}
|
|
|
|
$overallStats = PerformanceTestHelper::calculateStatistics($operationTimes);
|
|
echo " Overall: " . PerformanceTestHelper::formatStatistics($overallStats) . "\n";
|
|
|
|
// Performance should not degrade significantly with concurrency
|
|
$this->assertLessThan(50.0, $overallStats['avg'], "Database operations too slow at concurrency {$concurrency}");
|
|
}
|
|
}
|
|
|
|
public function testQueryOptimizationEffectiveness(): void
|
|
{
|
|
echo "\nQuery Optimization Effectiveness Test:\n";
|
|
|
|
// Create test data with specific patterns to test optimization
|
|
$workers = $this->createWorkers(500, 20);
|
|
$this->registerWorkers($workers);
|
|
|
|
$jobs = PerformanceTestHelper::createBulkJobs(2000);
|
|
foreach ($jobs as $job) {
|
|
$this->distributionService->distributeJob($job);
|
|
}
|
|
|
|
// Test complex queries that should benefit from optimization
|
|
$complexQueries = [
|
|
'workers_with_capacity_filter' => function () {
|
|
return $this->getWorkersByCapacityRange(15, 25);
|
|
},
|
|
'jobs_with_multiple_filters' => function () {
|
|
return $this->getJobsWithFilters(JobStatus::PENDING, \App\Framework\Queue\Jobs\JobPriority::NORMAL);
|
|
},
|
|
'job_count_aggregation' => function () {
|
|
return $this->getJobCountsByStatus();
|
|
},
|
|
'worker_utilization_stats' => function () {
|
|
return $this->getWorkerUtilizationStats();
|
|
},
|
|
];
|
|
|
|
foreach ($complexQueries as $queryName => $queryFunction) {
|
|
$times = [];
|
|
|
|
for ($i = 0; $i < 50; $i++) {
|
|
$time = PerformanceTestHelper::measureTime($queryFunction);
|
|
$times[] = $time;
|
|
}
|
|
|
|
$stats = PerformanceTestHelper::calculateStatistics($times);
|
|
echo "{$queryName}: " . PerformanceTestHelper::formatStatistics($stats) . "\n";
|
|
|
|
// Complex queries should still be reasonably fast
|
|
$this->assertLessThan(20.0, $stats['avg'], "Complex query {$queryName} not optimized enough");
|
|
$this->assertLessThan(50.0, $stats['p95'], "Complex query {$queryName} P95 not optimized enough");
|
|
}
|
|
}
|
|
|
|
public function testTransactionPerformance(): void
|
|
{
|
|
echo "\nTransaction Performance Test:\n";
|
|
|
|
$workers = $this->createWorkers(10, 20);
|
|
$this->registerWorkers($workers);
|
|
|
|
// Test transaction overhead
|
|
$transactionSizes = [1, 5, 10, 50, 100];
|
|
|
|
foreach ($transactionSizes as $size) {
|
|
$transactionTimes = [];
|
|
|
|
for ($iteration = 0; $iteration < 20; $iteration++) {
|
|
$time = PerformanceTestHelper::measureTime(function () use ($size, $iteration) {
|
|
$pdo = $this->database->getConnection();
|
|
|
|
try {
|
|
$pdo->beginTransaction();
|
|
|
|
for ($i = 0; $i < $size; $i++) {
|
|
$job = PerformanceTestHelper::createTestJob("tx_job_{$iteration}_{$i}");
|
|
$this->distributionService->distributeJob($job);
|
|
}
|
|
|
|
$pdo->commit();
|
|
} catch (\Exception $e) {
|
|
$pdo->rollBack();
|
|
|
|
throw $e;
|
|
}
|
|
});
|
|
|
|
$transactionTimes[] = $time;
|
|
}
|
|
|
|
$stats = PerformanceTestHelper::calculateStatistics($transactionTimes);
|
|
$timePerOperation = $stats['avg'] / $size;
|
|
|
|
echo sprintf(
|
|
"Transaction size %3d: %6.1fms total (%5.2fms/operation)\n",
|
|
$size,
|
|
$stats['avg'],
|
|
$timePerOperation
|
|
);
|
|
|
|
// Transaction overhead should be reasonable
|
|
$this->assertLessThan(200.0, $stats['avg'], "Transaction time too high for size {$size}");
|
|
|
|
$this->cleanupJobs();
|
|
}
|
|
}
|
|
|
|
private function createWorkers(int $count, int $capacity, WorkerStatus $status = WorkerStatus::AVAILABLE): array
|
|
{
|
|
$workers = [];
|
|
for ($i = 1; $i <= $count; $i++) {
|
|
$workers[] = PerformanceTestHelper::createTestWorker(
|
|
"db_perf_worker_{$i}",
|
|
$capacity,
|
|
$status
|
|
);
|
|
}
|
|
|
|
return $workers;
|
|
}
|
|
|
|
private function registerWorkers(array $workers): void
|
|
{
|
|
foreach ($workers as $worker) {
|
|
$this->workerRegistry->registerWorker($worker);
|
|
}
|
|
}
|
|
|
|
private function updateWorkerStatus(string $workerId, WorkerStatus $status): void
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->prepare('UPDATE workers SET status = ? WHERE id = ?');
|
|
$stmt->execute([$status->value, $workerId]);
|
|
}
|
|
|
|
private function updateJobStatus(string $jobId, JobStatus $status): void
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->prepare('UPDATE jobs SET status = ? WHERE id = ?');
|
|
$stmt->execute([$status->value, $jobId]);
|
|
}
|
|
|
|
private function getJobById(string $jobId): ?array
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE id = ?');
|
|
$stmt->execute([$jobId]);
|
|
|
|
return $stmt->fetch(\PDO::FETCH_ASSOC) ?: null;
|
|
}
|
|
|
|
private function getJobsByStatus(JobStatus $status): array
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE status = ? LIMIT 100');
|
|
$stmt->execute([$status->value]);
|
|
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
private function getJobsByWorker(string $workerId): array
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE worker_id = ? LIMIT 100');
|
|
$stmt->execute([$workerId]);
|
|
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
private function getJobsByPriority(\App\Framework\Queue\Jobs\JobPriority $priority): array
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE priority = ? LIMIT 100');
|
|
$stmt->execute([$priority->value]);
|
|
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
private function getJobsByQueue(string $queueName): array
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->prepare('SELECT * FROM jobs WHERE queue_name = ? LIMIT 100');
|
|
$stmt->execute([$queueName]);
|
|
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
private function getWorkersByCapacityRange(int $minCapacity, int $maxCapacity): array
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->prepare('SELECT * FROM workers WHERE capacity BETWEEN ? AND ?');
|
|
$stmt->execute([$minCapacity, $maxCapacity]);
|
|
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
private function getJobsWithFilters(JobStatus $status, \App\Framework\Queue\Jobs\JobPriority $priority): array
|
|
{
|
|
$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);
|
|
}
|
|
|
|
private function getJobCountsByStatus(): array
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->query('SELECT status, COUNT(*) as count FROM jobs GROUP BY status');
|
|
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
private function getWorkerUtilizationStats(): array
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$stmt = $pdo->query('
|
|
SELECT
|
|
w.status,
|
|
AVG(w.capacity) as avg_capacity,
|
|
COUNT(*) as worker_count,
|
|
COUNT(j.id) as job_count
|
|
FROM workers w
|
|
LEFT JOIN jobs j ON w.id = j.worker_id
|
|
GROUP BY w.status
|
|
');
|
|
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
private function cleanupJobs(): void
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$pdo->exec('DELETE FROM jobs');
|
|
}
|
|
|
|
private function createTestDatabase(): DatabaseManager
|
|
{
|
|
$pdo = new \PDO('sqlite::memory:');
|
|
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
|
|
|
$pdo->exec('
|
|
CREATE TABLE workers (
|
|
id TEXT PRIMARY KEY,
|
|
queue_names TEXT NOT NULL,
|
|
capacity INTEGER NOT NULL,
|
|
status TEXT NOT NULL,
|
|
last_heartbeat TEXT NOT NULL,
|
|
metadata TEXT
|
|
)
|
|
');
|
|
|
|
$pdo->exec('
|
|
CREATE TABLE jobs (
|
|
id TEXT PRIMARY KEY,
|
|
type TEXT NOT NULL,
|
|
payload TEXT NOT NULL,
|
|
queue_name TEXT NOT NULL,
|
|
priority INTEGER NOT NULL,
|
|
status TEXT NOT NULL,
|
|
worker_id TEXT,
|
|
created_at TEXT NOT NULL,
|
|
started_at TEXT,
|
|
completed_at TEXT,
|
|
attempts INTEGER DEFAULT 0,
|
|
error_message TEXT
|
|
)
|
|
');
|
|
|
|
// Comprehensive indexes for performance testing
|
|
$pdo->exec('CREATE INDEX idx_workers_id ON workers(id)');
|
|
$pdo->exec('CREATE INDEX idx_workers_status ON workers(status)');
|
|
$pdo->exec('CREATE INDEX idx_workers_capacity ON workers(capacity)');
|
|
$pdo->exec('CREATE INDEX idx_workers_status_capacity ON workers(status, capacity)');
|
|
|
|
$pdo->exec('CREATE INDEX idx_jobs_id ON jobs(id)');
|
|
$pdo->exec('CREATE INDEX idx_jobs_status ON jobs(status)');
|
|
$pdo->exec('CREATE INDEX idx_jobs_priority ON jobs(priority)');
|
|
$pdo->exec('CREATE INDEX idx_jobs_queue ON jobs(queue_name)');
|
|
$pdo->exec('CREATE INDEX idx_jobs_worker ON jobs(worker_id)');
|
|
$pdo->exec('CREATE INDEX idx_jobs_status_priority ON jobs(status, priority)');
|
|
$pdo->exec('CREATE INDEX idx_jobs_created ON jobs(created_at)');
|
|
|
|
return new DatabaseManager($pdo);
|
|
}
|
|
|
|
private function cleanupTestData(): void
|
|
{
|
|
$pdo = $this->database->getConnection();
|
|
$pdo->exec('DELETE FROM workers');
|
|
$pdo->exec('DELETE FROM jobs');
|
|
}
|
|
}
|