Class: Fractor::Workflow::JobDependencyValidator
- Inherits:
-
Object
- Object
- Fractor::Workflow::JobDependencyValidator
- Defined in:
- lib/fractor/workflow/job_dependency_validator.rb
Overview
Validates job dependencies in workflows. Ensures dependencies exist and are acyclic.
This validator prevents runtime errors by catching configuration issues before workflow execution begins.
Defined Under Namespace
Classes: DependencyError
Instance Method Summary collapse
-
#check_circular_dependencies ⇒ true
Check for circular dependencies using depth-first search.
-
#check_missing_dependencies ⇒ true
Check that all job dependencies exist.
-
#dfs_cycle_check(job, visited, path) ⇒ Array<String>?
DFS cycle detection that returns the cycle path if found.
-
#initialize(jobs) ⇒ JobDependencyValidator
constructor
A new instance of JobDependencyValidator.
-
#validate! ⇒ true
Validate all job dependencies.
Constructor Details
#initialize(jobs) ⇒ JobDependencyValidator
Returns a new instance of JobDependencyValidator.
14 15 16 17 |
# File 'lib/fractor/workflow/job_dependency_validator.rb', line 14 def initialize(jobs) @jobs = jobs @jobs_by_name = build_jobs_index end |
Instance Method Details
#check_circular_dependencies ⇒ true
Check for circular dependencies using depth-first search.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/fractor/workflow/job_dependency_validator.rb', line 34 def check_circular_dependencies visited = Set.new path = [] # Track current path as an array @jobs.each do |job| next if visited.include?(job.name) cycle = dfs_cycle_check(job, visited, path) if cycle cycle_path = cycle.join(" -> ") raise DependencyError, "Circular dependency detected: #{cycle_path}" end end true end |
#check_missing_dependencies ⇒ true
Check that all job dependencies exist.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/fractor/workflow/job_dependency_validator.rb', line 93 def check_missing_dependencies missing = [] @jobs.each do |job| job.dependencies.each do |dep_name| unless @jobs_by_name.key?(dep_name) missing << "#{job.name} depends on non-existent job '#{dep_name}'" end end end return true if missing.empty? raise DependencyError, "Missing dependencies:\n - #{missing.join("\n - ")}" end |
#dfs_cycle_check(job, visited, path) ⇒ Array<String>?
DFS cycle detection that returns the cycle path if found.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/fractor/workflow/job_dependency_validator.rb', line 57 def dfs_cycle_check(job, visited, path) return nil unless job # If this job is in the current path, we found a cycle if path.include?(job.name) # Extract the cycle portion cycle_start_index = path.index(job.name) return path[cycle_start_index..] + [job.name] end # If we've already fully explored this job, no cycle from here return nil if visited.include?(job.name) # Add to current path path << job.name # Check all dependencies job.dependencies.each do |dep_name| dep_job = @jobs_by_name[dep_name] next unless dep_job cycle = dfs_cycle_check(dep_job, visited, path) return cycle if cycle end # Remove from path and mark as visited path.pop visited.add(job.name) nil end |
#validate! ⇒ true
Validate all job dependencies. Raises DependencyError if any validation fails.
24 25 26 27 28 |
# File 'lib/fractor/workflow/job_dependency_validator.rb', line 24 def validate! check_missing_dependencies check_circular_dependencies true end |