Class: Tasker::Functions::FunctionBasedStepReadinessStatus

Inherits:
FunctionWrapper
  • Object
show all
Defined in:
lib/tasker/functions/function_based_step_readiness_status.rb

Overview

Function-based implementation of StepReadinessStatus Maintains the same interface as the view-based model but uses SQL functions for performance

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from FunctionWrapper

connection, convert_array_bind, from_sql_function, #readonly?, single_from_sql_function

Class Method Details

.blocked_by_dependencies_for_task(task_id) ⇒ Object



52
53
54
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 52

def self.blocked_by_dependencies_for_task(task_id)
  for_task(task_id).reject(&:dependencies_satisfied)
end

.blocked_by_retry_for_task(task_id) ⇒ Object



56
57
58
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 56

def self.blocked_by_retry_for_task(task_id)
  for_task(task_id).reject(&:retry_eligible)
end

.complete_for_task(task_id) ⇒ Object



72
73
74
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 72

def self.complete_for_task(task_id)
  for_task(task_id).select { |s| s.current_state.in?(%w[complete resolved_manually]) }
end

.failed_for_task(task_id) ⇒ Object



64
65
66
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 64

def self.failed_for_task(task_id)
  for_task(task_id).select { |s| s.current_state == 'error' }
end

.for_steps(task_id, step_ids) ⇒ Object



35
36
37
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 35

def self.for_steps(task_id, step_ids)
  for_task(task_id, step_ids)
end

.for_task(task_id, step_ids = nil) ⇒ Object

Class methods that use SQL functions



29
30
31
32
33
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 29

def self.for_task(task_id, step_ids = nil)
  sql = 'SELECT * FROM get_step_readiness_status($1::BIGINT, $2::BIGINT[])'
  binds = [task_id, step_ids]
  from_sql_function(sql, binds, 'StepReadinessStatus Load')
end

.for_tasks(task_ids) ⇒ Object



39
40
41
42
43
44
45
46
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 39

def self.for_tasks(task_ids)
  return [] if task_ids.empty?

  # Use the batch function to get steps for multiple tasks efficiently
  sql = 'SELECT * FROM get_step_readiness_status_batch($1::BIGINT[])'
  binds = [task_ids]
  from_sql_function(sql, binds, 'StepReadinessStatus Batch Load')
end

.in_progress_for_task(task_id) ⇒ Object



68
69
70
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 68

def self.in_progress_for_task(task_id)
  for_task(task_id).select { |s| s.current_state == 'in_progress' }
end

.pending_for_task(task_id) ⇒ Object



60
61
62
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 60

def self.pending_for_task(task_id)
  for_task(task_id).select { |s| s.current_state == 'pending' }
end

.ready_for_task(task_id) ⇒ Object



48
49
50
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 48

def self.ready_for_task(task_id)
  for_task(task_id).select(&:ready_for_execution)
end

Instance Method Details

#backoff_typeObject



117
118
119
120
121
122
123
124
125
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 117

def backoff_type
  if backoff_request_seconds.present? && last_attempted_at.present?
    'explicit_backoff'
  elsif last_failure_at.present?
    'exponential_backoff'
  else
    'no_backoff'
  end
end

#blocking_reasonObject



81
82
83
84
85
86
87
88
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 81

def blocking_reason
  return nil if ready_for_execution
  return 'dependencies_not_satisfied' unless dependencies_satisfied
  return 'retry_not_eligible' unless retry_eligible
  return 'invalid_state' unless %w[pending error].include?(current_state)

  'unknown'
end

#can_execute_now?Boolean

Instance methods (same as original model)

Returns:

  • (Boolean)


77
78
79
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 77

def can_execute_now?
  ready_for_execution
end

#dependency_statusObject



97
98
99
100
101
102
103
104
105
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 97

def dependency_status
  if total_parents.zero?
    'no_dependencies'
  elsif dependencies_satisfied
    'all_satisfied'
  else
    "#{completed_parents || 0}/#{total_parents || 0}_satisfied"
  end
end

#detailed_statusObject



160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 160

def detailed_status
  {
    ready: ready_for_execution,
    current_state: current_state,
    dependencies: dependency_status,
    retry: retry_status,
    blocking_reason: blocking_reason,
    time_until_ready: time_until_ready,
    backoff_type: backoff_type,
    effective_backoff_seconds: effective_backoff_seconds
  }
end

#effective_backoff_secondsObject



127
128
129
130
131
132
133
134
135
136
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 127

def effective_backoff_seconds
  if backoff_request_seconds.present?
    backoff_request_seconds
  elsif attempts.present? && attempts.positive?
    # Calculate default exponential backoff (base_delay * 2^attempts, capped at 30)
    [2**attempts, 30].min
  else
    0
  end
end

#retry_statusObject



107
108
109
110
111
112
113
114
115
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 107

def retry_status
  if attempts >= retry_limit
    'max_retries_reached'
  elsif retry_eligible
    'retry_eligible'
  else
    'waiting_for_backoff'
  end
end

#taskObject



178
179
180
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 178

def task
  @task ||= Tasker::Task.find(task_id)
end

#time_until_readyObject



90
91
92
93
94
95
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 90

def time_until_ready
  return 0 if ready_for_execution
  return nil unless next_retry_at

  [(next_retry_at - Time.current).to_i, 0].max
end

#to_hObject



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 138

def to_h
  {
    workflow_step_id: workflow_step_id,
    task_id: task_id,
    named_step_id: named_step_id,
    name: name,
    current_state: current_state,
    dependencies_satisfied: dependencies_satisfied,
    retry_eligible: retry_eligible,
    ready_for_execution: ready_for_execution,
    last_failure_at: last_failure_at,
    next_retry_at: next_retry_at,
    total_parents: total_parents,
    completed_parents: completed_parents,
    attempts: attempts,
    retry_limit: retry_limit,
    backoff_request_seconds: backoff_request_seconds,
    last_attempted_at: last_attempted_at,
    detailed_status: detailed_status
  }
end

#workflow_stepObject

Associations (lazy-loaded)



174
175
176
# File 'lib/tasker/functions/function_based_step_readiness_status.rb', line 174

def workflow_step
  @workflow_step ||= Tasker::WorkflowStep.find(workflow_step_id)
end