Class: Ace::Assign::Models::QueueState
- Inherits:
-
Object
- Object
- Ace::Assign::Models::QueueState
- Defined in:
- lib/ace/assign/models/queue_state.rb
Overview
Queue state model representing a snapshot of the work queue.
Pure data carrier with no business logic (ATOM pattern). Provides convenient accessors for queue analysis.
Instance Attribute Summary collapse
-
#assignment ⇒ Object
readonly
Returns the value of attribute assignment.
-
#steps ⇒ Object
readonly
Returns the value of attribute steps.
Instance Method Summary collapse
-
#all_numbers ⇒ Array<String>
Get all step numbers as an array.
-
#ancestor_chain(number) ⇒ Array<String>
Build ancestor chain from closest parent to root.
-
#assignment_state ⇒ Symbol
Computed assignment state based on step statuses.
-
#children_of(parent_number) ⇒ Array<Step>
Get all direct children of a step (O(1) via index).
-
#complete? ⇒ Boolean
Check if all steps are complete (no pending or in_progress).
-
#current ⇒ Step?
Get current in-progress step.
-
#current_in_subtree(root_number) ⇒ Step?
Get the current in-progress step within a subtree.
-
#descendants_of(parent_number) ⇒ Array<Step>
Get all descendants (children, grandchildren, etc.) of a step.
-
#done ⇒ Array<Step>
Get all done steps.
-
#empty? ⇒ Boolean
Check if queue is empty.
-
#failed ⇒ Array<Step>
Get all failed steps.
-
#find_by_number(number) ⇒ Step?
Get step by number.
-
#has_incomplete_children?(parent_number) ⇒ Boolean
Check if a step has any incomplete children.
-
#hierarchical ⇒ Array<Hash>
Build hierarchical structure for display.
-
#in_progress_in_subtree(root_number) ⇒ Array<Step>
Get all in-progress steps within a subtree.
-
#in_progress_steps ⇒ Array<Step>
Get all in-progress steps.
-
#in_subtree?(root_number, step_number) ⇒ Boolean
Check whether a step number belongs to a subtree rooted at root_number.
-
#initialize(steps:, assignment:) ⇒ QueueState
constructor
A new instance of QueueState.
-
#last ⇒ Step?
Get last step in queue.
-
#last_done ⇒ Step?
Get last completed step.
-
#nearest_fork_ancestor(number) ⇒ Step?
Find nearest ancestor (or self) that has context: fork.
-
#next_pending ⇒ Step?
Get next pending step.
-
#next_workable ⇒ Step?
Get next workable step considering hierarchy.
-
#next_workable_in_subtree(root_number) ⇒ Step?
Get next workable step constrained to a subtree.
-
#pending ⇒ Array<Step>
Get all pending steps.
-
#recently_active?(threshold: 3600) ⇒ Boolean
Check if the current in_progress step has recent activity.
-
#size ⇒ Integer
Total step count.
-
#subtree_complete?(root_number) ⇒ Boolean
Check whether all steps in a subtree are complete.
-
#subtree_failed?(root_number) ⇒ Boolean
Check whether a subtree has at least one failed step.
-
#subtree_steps(root_number) ⇒ Array<Step>
Get all steps in a subtree (root + descendants), preserving queue order.
-
#summary ⇒ Hash
Summary for display.
-
#top_level ⇒ Array<Step>
Get top-level (root) steps only.
Constructor Details
#initialize(steps:, assignment:) ⇒ QueueState
Returns a new instance of QueueState.
20 21 22 23 24 |
# File 'lib/ace/assign/models/queue_state.rb', line 20 def initialize(steps:, assignment:) @steps = steps.freeze @assignment = assignment @children_index = build_children_index(steps) end |
Instance Attribute Details
#assignment ⇒ Object (readonly)
Returns the value of attribute assignment.
16 17 18 |
# File 'lib/ace/assign/models/queue_state.rb', line 16 def assignment @assignment end |
#steps ⇒ Object (readonly)
Returns the value of attribute steps.
16 17 18 |
# File 'lib/ace/assign/models/queue_state.rb', line 16 def steps @steps end |
Instance Method Details
#all_numbers ⇒ Array<String>
Get all step numbers as an array
280 281 282 |
# File 'lib/ace/assign/models/queue_state.rb', line 280 def all_numbers steps.map(&:number) end |
#ancestor_chain(number) ⇒ Array<String>
Build ancestor chain from closest parent to root.
228 229 230 231 232 233 234 235 236 |
# File 'lib/ace/assign/models/queue_state.rb', line 228 def ancestor_chain(number) chain = [] parent = Atoms::StepNumbering.parent_of(number) while parent chain << parent parent = Atoms::StepNumbering.parent_of(parent) end chain end |
#assignment_state ⇒ Symbol
Computed assignment state based on step statuses
States (checked in priority order):
-
:empty - No steps in queue
-
:completed - All steps complete (done or failed)
-
:failed - Has failed step(s) but NOT all complete (stuck)
-
:running - Has in_progress step with recent activity (< 1 hour)
-
:stalled - Has in_progress step but stale (> 1 hour)
-
:paused - Has pending but no in_progress (interrupted)
115 116 117 118 119 120 121 122 123 |
# File 'lib/ace/assign/models/queue_state.rb', line 115 def assignment_state return :empty if empty? return :completed if complete? return :failed if failed.any? return :running if current && recently_active? return :stalled if current :paused end |
#children_of(parent_number) ⇒ Array<Step>
Get all direct children of a step (O(1) via index)
149 150 151 |
# File 'lib/ace/assign/models/queue_state.rb', line 149 def children_of(parent_number) @children_index[parent_number] || [] end |
#complete? ⇒ Boolean
Check if all steps are complete (no pending or in_progress)
70 71 72 |
# File 'lib/ace/assign/models/queue_state.rb', line 70 def complete? steps.all?(&:complete?) end |
#current ⇒ Step?
Get current in-progress step
28 29 30 |
# File 'lib/ace/assign/models/queue_state.rb', line 28 def current in_progress_steps.first end |
#current_in_subtree(root_number) ⇒ Step?
Get the current in-progress step within a subtree.
200 201 202 |
# File 'lib/ace/assign/models/queue_state.rb', line 200 def current_in_subtree(root_number) in_progress_in_subtree(root_number).first end |
#descendants_of(parent_number) ⇒ Array<Step>
Get all descendants (children, grandchildren, etc.) of a step
156 157 158 |
# File 'lib/ace/assign/models/queue_state.rb', line 156 def descendants_of(parent_number) steps.select { |s| Atoms::StepNumbering.child_of?(s.number, parent_number) } end |
#done ⇒ Array<Step>
Get all done steps
46 47 48 |
# File 'lib/ace/assign/models/queue_state.rb', line 46 def done steps.select { |s| s.status == :done } end |
#empty? ⇒ Boolean
Check if queue is empty
64 65 66 |
# File 'lib/ace/assign/models/queue_state.rb', line 64 def empty? steps.empty? end |
#failed ⇒ Array<Step>
Get all failed steps
52 53 54 |
# File 'lib/ace/assign/models/queue_state.rb', line 52 def failed steps.select { |s| s.status == :failed } end |
#find_by_number(number) ⇒ Step?
Get step by number
77 78 79 80 81 82 83 84 |
# File 'lib/ace/assign/models/queue_state.rb', line 77 def find_by_number(number) # Normalize to string without leading zeros for comparison normalized = number.to_s.sub(/^0+/, "") steps.find do |s| next unless s.number s.number.sub(/^0+/, "") == normalized || s.number == number.to_s end end |
#has_incomplete_children?(parent_number) ⇒ Boolean
Check if a step has any incomplete children
259 260 261 |
# File 'lib/ace/assign/models/queue_state.rb', line 259 def has_incomplete_children?(parent_number) children_of(parent_number).any? { |s| s.status != :done } end |
#hierarchical ⇒ Array<Hash>
Build hierarchical structure for display
292 293 294 |
# File 'lib/ace/assign/models/queue_state.rb', line 292 def hierarchical build_hierarchy(nil) end |
#in_progress_in_subtree(root_number) ⇒ Array<Step>
Get all in-progress steps within a subtree.
208 209 210 211 |
# File 'lib/ace/assign/models/queue_state.rb', line 208 def in_progress_in_subtree(root_number) subtree_steps(root_number) .select { |s| s.status == :in_progress } end |
#in_progress_steps ⇒ Array<Step>
Get all in-progress steps
34 35 36 |
# File 'lib/ace/assign/models/queue_state.rb', line 34 def in_progress_steps steps.select { |s| s.status == :in_progress } end |
#in_subtree?(root_number, step_number) ⇒ Boolean
Check whether a step number belongs to a subtree rooted at root_number.
165 166 167 |
# File 'lib/ace/assign/models/queue_state.rb', line 165 def in_subtree?(root_number, step_number) step_number == root_number || Atoms::StepNumbering.child_of?(step_number, root_number) end |
#last ⇒ Step?
Get last step in queue
88 89 90 |
# File 'lib/ace/assign/models/queue_state.rb', line 88 def last steps.last end |
#last_done ⇒ Step?
Get last completed step
94 95 96 |
# File 'lib/ace/assign/models/queue_state.rb', line 94 def last_done done.last end |
#nearest_fork_ancestor(number) ⇒ Step?
Find nearest ancestor (or self) that has context: fork.
242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/ace/assign/models/queue_state.rb', line 242 def nearest_fork_ancestor(number) step = find_by_number(number) return nil unless step return step if step.fork? ancestor_chain(number).each do |ancestor_number| ancestor = find_by_number(ancestor_number) return ancestor if ancestor&.fork? end nil end |
#next_pending ⇒ Step?
Get next pending step
58 59 60 |
# File 'lib/ace/assign/models/queue_state.rb', line 58 def next_pending pending.first end |
#next_workable ⇒ Step?
Get next workable step considering hierarchy. A step is workable if it’s pending and has no incomplete children. Prefers children of current/recent work.
267 268 269 270 271 272 273 274 275 276 |
# File 'lib/ace/assign/models/queue_state.rb', line 267 def next_workable # First, find pending steps pending_steps = pending # Filter to steps that don't have incomplete children workable = pending_steps.reject { |s| has_incomplete_children?(s.number) } # Return first workable step (already sorted by number) workable.first end |
#next_workable_in_subtree(root_number) ⇒ Step?
Get next workable step constrained to a subtree.
217 218 219 220 221 222 |
# File 'lib/ace/assign/models/queue_state.rb', line 217 def next_workable_in_subtree(root_number) subtree_steps(root_number) .select { |s| s.status == :pending } .reject { |s| has_incomplete_children?(s.number) } .first end |
#pending ⇒ Array<Step>
Get all pending steps
40 41 42 |
# File 'lib/ace/assign/models/queue_state.rb', line 40 def pending steps.select { |s| s.status == :pending } end |
#recently_active?(threshold: 3600) ⇒ Boolean
Check if the current in_progress step has recent activity
128 129 130 131 132 |
# File 'lib/ace/assign/models/queue_state.rb', line 128 def recently_active?(threshold: 3600) return false unless current&.started_at (Time.now - current.started_at) < threshold end |
#size ⇒ Integer
Total step count
100 101 102 |
# File 'lib/ace/assign/models/queue_state.rb', line 100 def size steps.size end |
#subtree_complete?(root_number) ⇒ Boolean
Check whether all steps in a subtree are complete.
181 182 183 184 185 186 |
# File 'lib/ace/assign/models/queue_state.rb', line 181 def subtree_complete?(root_number) scoped = subtree_steps(root_number) return false if scoped.empty? scoped.all?(&:complete?) end |
#subtree_failed?(root_number) ⇒ Boolean
Check whether a subtree has at least one failed step.
192 193 194 |
# File 'lib/ace/assign/models/queue_state.rb', line 192 def subtree_failed?(root_number) subtree_steps(root_number).any? { |s| s.status == :failed } end |
#subtree_steps(root_number) ⇒ Array<Step>
Get all steps in a subtree (root + descendants), preserving queue order.
173 174 175 |
# File 'lib/ace/assign/models/queue_state.rb', line 173 def subtree_steps(root_number) steps.select { |s| in_subtree?(root_number, s.number) } end |
#summary ⇒ Hash
Summary for display
136 137 138 139 140 141 142 143 144 |
# File 'lib/ace/assign/models/queue_state.rb', line 136 def summary { total: size, done: done.size, in_progress: in_progress_steps.size, pending: pending.size, failed: failed.size } end |
#top_level ⇒ Array<Step>
Get top-level (root) steps only
286 287 288 |
# File 'lib/ace/assign/models/queue_state.rb', line 286 def top_level steps.select { |s| Atoms::StepNumbering.top_level?(s.number) } end |