Module: Request::Statemachine

Included in:
Request
Defined in:
app/models/request/statemachine.rb

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

COMPLETED_STATE =
%w[passed failed]
OPENED_STATE =
%w[pending blocked started]
ACTIVE =
%w(passed pending blocked started)
INACTIVE =
%w[failed cancelled]
SORT_ORDER =
%w[pending blocked hold started passed failed cancelled]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'app/models/request/statemachine.rb', line 37

def self.included(base)
  base.class_eval do
    extend ClassMethods

    ## State machine
    aasm column: :state, whiny_persistence: true do
      state :pending,   initial: true
      state :started,   after_enter: :on_started
      state :failed,    after_enter: :on_failed
      state :passed,    after_enter: :on_passed
      state :cancelled, after_enter: :on_cancelled
      state :blocked,   after_enter: :on_blocked
      state :hold,      after_enter: :on_hold

      event :hold do
        transitions to: :hold, from: [:pending]
      end

      # State Machine events
      event :start do
        transitions to: :started, from: [:pending, :hold]
      end

      event :pass do
        transitions to: :passed, from: [:started]
      end

      event :fail do
        transitions to: :failed, from: [:started]
      end

      event :retrospective_pass do
        transitions to: :passed, from: [:failed]
      end

      event :retrospective_fail do
        transitions to: :failed, from: [:passed]
      end

      event :block do
        transitions to: :blocked, from: [:pending]
      end

      event :unblock do
        transitions to: :pending, from: [:blocked]
      end

      event :detach do
        transitions to: :pending, from: [:cancelled]
      end

      event :reset do
        transitions to: :pending, from: [:hold]
      end

      event :cancel do
        transitions to: :cancelled, from: [:started, :hold]
      end

      event :return do
        transitions to: :pending, from: [:failed, :passed]
      end

      event :cancel_completed do
        transitions to: :cancelled, from: [:failed, :passed]
      end

      event :cancel_from_upstream, manual_only?: true do
        transitions to: :cancelled, from: [:pending]
      end

      event :cancel_before_started do
        transitions to: :cancelled, from: [:pending, :hold]
      end

      event :submission_cancelled, manual_only?: true do
        transitions to: :cancelled, from: [:pending, :cancelled]
      end

      event :fail_from_upstream, manual_only?: true do
        transitions to: :cancelled, from: [:pending]
        transitions to: :failed,    from: [:started]
        transitions to: :failed,    from: [:passed]
      end
    end

    scope :for_state, ->(state) { where(state: state) }

    scope :completed,        -> { where(state: COMPLETED_STATE) }

    scope :pipeline_pending, -> { where(state: 'pending') } #  we don't want the blocked one here }
    scope :pending,          -> { where(state: %w[pending blocked]) } # block is a kind of substate of pending }

    scope :started,          -> { where(state: 'started') }
    scope :cancelled,        -> { where(state: 'cancelled') }

    scope :opened,           -> { where(state: OPENED_STATE) }
    scope :closed,           -> { where(state: %w[passed failed cancelled]) }
  end
end

Instance Method Details

#cancellable?Boolean


214
215
216
# File 'app/models/request/statemachine.rb', line 214

def cancellable?
  %w(pending cancelled).include?(state)
end

#change_decision!void

Deprecated.

Favour retrospective_pass and retrospective_fail! instead. It is incredibly unlikely that you wish to arbitrarily toggle the state of a request And instead you probably have an explicit target state in mind. Use that instead.

This method returns an undefined value.

Toggles passed request to failed, and failed requests to pass.

Raises:

  • (StandardError)

167
168
169
170
171
172
# File 'app/models/request/statemachine.rb', line 167

def change_decision!
  return retrospective_fail! if passed?
  return retrospective_pass! if failed?

  raise StandardError, 'Can only use change decision on passed or failed requests'
end

#closed?Boolean


206
207
208
# File 'app/models/request/statemachine.rb', line 206

def closed?
  %w(passed failed cancelled aborted).include?(state)
end

#failed_downstream!Object


194
195
196
# File 'app/models/request/statemachine.rb', line 194

def failed_downstream!
  # Do nothing by default
end

#failed_upstream!Object


190
191
192
# File 'app/models/request/statemachine.rb', line 190

def failed_upstream!
  fail_from_upstream! unless failed?
end

#finished?Boolean


198
199
200
# File 'app/models/request/statemachine.rb', line 198

def finished?
  passed? || failed?
end

#on_blockedObject


184
185
# File 'app/models/request/statemachine.rb', line 184

def on_blocked
end

#on_cancelledObject


181
182
# File 'app/models/request/statemachine.rb', line 181

def on_cancelled
end

#on_failedObject


175
176
# File 'app/models/request/statemachine.rb', line 175

def on_failed
end

#on_holdObject


187
188
# File 'app/models/request/statemachine.rb', line 187

def on_hold
end

#on_passedObject


178
179
# File 'app/models/request/statemachine.rb', line 178

def on_passed
end

#on_startedObject

Default behaviour on started is to do nothing.


145
146
147
# File 'app/models/request/statemachine.rb', line 145

def on_started
  # Some subclasses may call transfer_aliquots below.
end

#open?Boolean


210
211
212
# File 'app/models/request/statemachine.rb', line 210

def open?
  %w(pending started).include?(state)
end

#terminated?Boolean


202
203
204
# File 'app/models/request/statemachine.rb', line 202

def terminated?
  failed? || cancelled?
end

#transfer_aliquotsObject

Aliquots are copied from the source asset to the target and updated with the project and study information from the request itself.


151
152
153
154
155
156
157
158
# File 'app/models/request/statemachine.rb', line 151

def transfer_aliquots
  target_asset.aliquots << asset.aliquots.map do |aliquot|
    aliquot.dup.tap do |clone|
      clone.study_id   = initial_study_id   || aliquot.study_id
      clone.project_id = initial_project_id || aliquot.project_id
    end
  end
end

#transition_to(target_state) ⇒ Object


218
219
220
# File 'app/models/request/statemachine.rb', line 218

def transition_to(target_state)
  aasm.fire!(suggested_transition_to(target_state))
end