docs: consolidate documentation into organized structure

- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
This commit is contained in:
2025-10-05 11:05:04 +02:00
parent 887847dde6
commit 5050c7d73a
36686 changed files with 196456 additions and 12398919 deletions

View File

@@ -0,0 +1,274 @@
<?php
declare(strict_types=1);
namespace App\Framework\Queue\Services;
use App\Framework\Queue\Contracts\JobDependencyManagerInterface;
use App\Framework\Queue\Contracts\JobChainManagerInterface;
use App\Framework\Queue\Contracts\QueueInterface;
use App\Framework\Queue\ValueObjects\Job;
use App\Framework\Logging\Logger;
final readonly class DependencyResolutionEngine
{
public function __construct(
private JobDependencyManagerInterface $dependencyManager,
private JobChainManagerInterface $chainManager,
private QueueInterface $queue,
private Logger $logger
) {}
/**
* Process job completion and resolve any dependent jobs that can now be executed
*/
public function resolveJobCompletion(string $jobId, bool $successful = true): array
{
$this->logger->info('Starting dependency resolution for completed job', [
'job_id' => $jobId,
'successful' => $successful
]);
$resolvedJobs = [];
// 1. Resolve individual job dependencies
$dependentJobs = $this->dependencyManager->resolveJobCompletion($jobId, $successful);
foreach ($dependentJobs as $dependentJobId) {
$resolvedJobs[] = [
'job_id' => $dependentJobId,
'type' => 'dependency_resolved',
'trigger_job' => $jobId
];
}
// 2. Handle job chain progression
$this->chainManager->handleJobCompletion($jobId, $successful);
// Get next jobs in any chains this job belongs to
$chains = $this->chainManager->getChainsForJob($jobId);
foreach ($chains as $chainEntry) {
if ($chainEntry->isRunning()) {
$nextJobId = $this->chainManager->getNextJobInChain($chainEntry->chainId, $jobId);
if ($nextJobId !== null) {
// Check if the next job has any other unsatisfied dependencies
if ($this->dependencyManager->canJobBeExecuted($nextJobId)) {
$resolvedJobs[] = [
'job_id' => $nextJobId,
'type' => 'chain_progression',
'chain_id' => $chainEntry->chainId,
'trigger_job' => $jobId
];
} else {
$this->logger->info('Next job in chain has unsatisfied dependencies', [
'chain_id' => $chainEntry->chainId,
'next_job_id' => $nextJobId,
'unsatisfied_deps' => count($this->dependencyManager->getUnsatisfiedDependencies($nextJobId))
]);
}
}
}
}
$this->logger->info('Dependency resolution completed', [
'trigger_job_id' => $jobId,
'resolved_jobs_count' => count($resolvedJobs),
'resolved_jobs' => array_column($resolvedJobs, 'job_id')
]);
return $resolvedJobs;
}
/**
* Get all jobs that are ready to be executed (no unsatisfied dependencies)
*/
public function getExecutableJobs(): array
{
$readyJobs = $this->dependencyManager->getReadyJobs();
$this->logger->debug('Found jobs ready for execution', [
'ready_jobs_count' => count($readyJobs),
'ready_jobs' => $readyJobs
]);
return $readyJobs;
}
/**
* Validate a job dependency graph for circular dependencies
*/
public function validateDependencyGraph(array $jobIds): array
{
$validationResults = [];
foreach ($jobIds as $jobId) {
$hasCircularDeps = $this->dependencyManager->hasCircularDependencies($jobId);
if ($hasCircularDeps) {
$dependencyChain = $this->dependencyManager->getDependencyChain($jobId);
$validationResults[] = [
'job_id' => $jobId,
'valid' => false,
'error' => 'circular_dependency',
'dependency_chain' => $dependencyChain
];
$this->logger->warning('Circular dependency detected', [
'job_id' => $jobId,
'dependency_chain' => $dependencyChain
]);
} else {
$validationResults[] = [
'job_id' => $jobId,
'valid' => true
];
}
}
return $validationResults;
}
/**
* Get dependency analysis for a job
*/
public function analyzeDependencies(string $jobId): array
{
$dependencies = $this->dependencyManager->getDependencies($jobId);
$dependents = $this->dependencyManager->getDependents($jobId);
$unsatisfiedDeps = $this->dependencyManager->getUnsatisfiedDependencies($jobId);
$dependencyChain = $this->dependencyManager->getDependencyChain($jobId);
$canExecute = $this->dependencyManager->canJobBeExecuted($jobId);
return [
'job_id' => $jobId,
'can_execute' => $canExecute,
'direct_dependencies' => array_map(fn($dep) => [
'depends_on_job_id' => $dep->dependsOnJobId,
'dependency_type' => $dep->dependencyType,
'is_satisfied' => $dep->isSatisfied,
'condition' => $dep->conditionExpression
], $dependencies),
'dependent_jobs' => array_map(fn($dep) => [
'dependent_job_id' => $dep->dependentJobId,
'dependency_type' => $dep->dependencyType,
'is_satisfied' => $dep->isSatisfied
], $dependents),
'unsatisfied_dependencies' => array_map(fn($dep) => [
'depends_on_job_id' => $dep->dependsOnJobId,
'dependency_type' => $dep->dependencyType,
'condition' => $dep->conditionExpression
], $unsatisfiedDeps),
'full_dependency_chain' => $dependencyChain,
'statistics' => [
'total_dependencies' => count($dependencies),
'satisfied_dependencies' => count($dependencies) - count($unsatisfiedDeps),
'unsatisfied_dependencies' => count($unsatisfiedDeps),
'total_dependents' => count($dependents),
'chain_depth' => count($dependencyChain)
]
];
}
/**
* Get analysis for job chains
*/
public function analyzeChains(string $jobId): array
{
$chains = $this->chainManager->getChainsForJob($jobId);
$chainAnalysis = [];
foreach ($chains as $chainEntry) {
$progress = $this->chainManager->getChainProgress($chainEntry->chainId);
$nextJob = $this->chainManager->getNextJobInChain($chainEntry->chainId, $jobId);
$chainAnalysis[] = [
'chain_id' => $chainEntry->chainId,
'name' => $chainEntry->name,
'status' => $chainEntry->status,
'execution_mode' => $chainEntry->executionMode,
'stop_on_failure' => $chainEntry->stopOnFailure,
'progress' => $progress,
'next_job_after_current' => $nextJob,
'job_position' => $this->getJobPositionInChain($jobId, $chainEntry),
'total_jobs' => count($chainEntry->getJobIdsArray())
];
}
return [
'job_id' => $jobId,
'chains' => $chainAnalysis,
'total_chains' => count($chains)
];
}
/**
* Comprehensive dependency health check
*/
public function performHealthCheck(): array
{
$this->logger->info('Starting dependency system health check');
$activeChains = $this->chainManager->getActiveChains();
$pendingChains = $this->chainManager->getPendingChains();
$readyJobs = $this->dependencyManager->getReadyJobs();
// Check for potential issues
$issues = [];
// Check for stalled chains (running for too long)
foreach ($activeChains as $chain) {
if ($chain->startedAt) {
$startTime = strtotime($chain->startedAt);
$hoursRunning = (time() - $startTime) / 3600;
if ($hoursRunning > 24) { // Configurable threshold
$issues[] = [
'type' => 'stalled_chain',
'chain_id' => $chain->chainId,
'hours_running' => round($hoursRunning, 2)
];
}
}
}
// Check for jobs with many unsatisfied dependencies (potential deadlocks)
foreach ($readyJobs as $jobId) {
$analysis = $this->analyzeDependencies($jobId);
if ($analysis['statistics']['unsatisfied_dependencies'] > 10) { // Configurable threshold
$issues[] = [
'type' => 'many_unsatisfied_dependencies',
'job_id' => $jobId,
'unsatisfied_count' => $analysis['statistics']['unsatisfied_dependencies']
];
}
}
$healthReport = [
'status' => count($issues) === 0 ? 'healthy' : 'issues_detected',
'timestamp' => date('Y-m-d H:i:s'),
'statistics' => [
'active_chains' => count($activeChains),
'pending_chains' => count($pendingChains),
'ready_jobs' => count($readyJobs),
'detected_issues' => count($issues)
],
'issues' => $issues
];
$this->logger->info('Dependency system health check completed', [
'status' => $healthReport['status'],
'issues_count' => count($issues)
]);
return $healthReport;
}
private function getJobPositionInChain(string $jobId, object $chainEntry): ?int
{
$jobIds = $chainEntry->getJobIdsArray();
return array_search($jobId, $jobIds, true) ?: null;
}
}