cadence-ruby 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +456 -0
- data/cadence.gemspec +9 -2
- data/lib/cadence-ruby.rb +1 -0
- data/lib/cadence.rb +176 -0
- data/lib/cadence/activity.rb +33 -0
- data/lib/cadence/activity/async_token.rb +34 -0
- data/lib/cadence/activity/context.rb +64 -0
- data/lib/cadence/activity/poller.rb +89 -0
- data/lib/cadence/activity/task_processor.rb +73 -0
- data/lib/cadence/activity/workflow_convenience_methods.rb +41 -0
- data/lib/cadence/client.rb +21 -0
- data/lib/cadence/client/errors.rb +8 -0
- data/lib/cadence/client/thrift_client.rb +380 -0
- data/lib/cadence/concerns/executable.rb +33 -0
- data/lib/cadence/concerns/typed.rb +40 -0
- data/lib/cadence/configuration.rb +36 -0
- data/lib/cadence/errors.rb +21 -0
- data/lib/cadence/executable_lookup.rb +25 -0
- data/lib/cadence/execution_options.rb +32 -0
- data/lib/cadence/json.rb +18 -0
- data/lib/cadence/metadata.rb +73 -0
- data/lib/cadence/metadata/activity.rb +28 -0
- data/lib/cadence/metadata/base.rb +17 -0
- data/lib/cadence/metadata/decision.rb +25 -0
- data/lib/cadence/metadata/workflow.rb +23 -0
- data/lib/cadence/metrics.rb +37 -0
- data/lib/cadence/metrics_adapters/log.rb +33 -0
- data/lib/cadence/metrics_adapters/null.rb +9 -0
- data/lib/cadence/middleware/chain.rb +30 -0
- data/lib/cadence/middleware/entry.rb +9 -0
- data/lib/cadence/retry_policy.rb +27 -0
- data/lib/cadence/saga/concern.rb +37 -0
- data/lib/cadence/saga/result.rb +22 -0
- data/lib/cadence/saga/saga.rb +24 -0
- data/lib/cadence/testing.rb +50 -0
- data/lib/cadence/testing/cadence_override.rb +112 -0
- data/lib/cadence/testing/future_registry.rb +27 -0
- data/lib/cadence/testing/local_activity_context.rb +17 -0
- data/lib/cadence/testing/local_workflow_context.rb +207 -0
- data/lib/cadence/testing/workflow_execution.rb +44 -0
- data/lib/cadence/testing/workflow_override.rb +36 -0
- data/lib/cadence/thread_local_context.rb +14 -0
- data/lib/cadence/thread_pool.rb +68 -0
- data/lib/cadence/types.rb +7 -0
- data/lib/cadence/utils.rb +17 -0
- data/lib/cadence/uuid.rb +19 -0
- data/lib/cadence/version.rb +1 -1
- data/lib/cadence/worker.rb +91 -0
- data/lib/cadence/workflow.rb +42 -0
- data/lib/cadence/workflow/context.rb +266 -0
- data/lib/cadence/workflow/convenience_methods.rb +34 -0
- data/lib/cadence/workflow/decision.rb +39 -0
- data/lib/cadence/workflow/decision_state_machine.rb +48 -0
- data/lib/cadence/workflow/decision_task_processor.rb +105 -0
- data/lib/cadence/workflow/dispatcher.rb +31 -0
- data/lib/cadence/workflow/execution_info.rb +45 -0
- data/lib/cadence/workflow/executor.rb +45 -0
- data/lib/cadence/workflow/future.rb +75 -0
- data/lib/cadence/workflow/history.rb +76 -0
- data/lib/cadence/workflow/history/event.rb +71 -0
- data/lib/cadence/workflow/history/event_target.rb +79 -0
- data/lib/cadence/workflow/history/window.rb +40 -0
- data/lib/cadence/workflow/poller.rb +74 -0
- data/lib/cadence/workflow/replay_aware_logger.rb +36 -0
- data/lib/cadence/workflow/serializer.rb +31 -0
- data/lib/cadence/workflow/serializer/base.rb +22 -0
- data/lib/cadence/workflow/serializer/cancel_timer.rb +19 -0
- data/lib/cadence/workflow/serializer/complete_workflow.rb +20 -0
- data/lib/cadence/workflow/serializer/fail_workflow.rb +21 -0
- data/lib/cadence/workflow/serializer/record_marker.rb +21 -0
- data/lib/cadence/workflow/serializer/request_activity_cancellation.rb +19 -0
- data/lib/cadence/workflow/serializer/schedule_activity.rb +54 -0
- data/lib/cadence/workflow/serializer/start_child_workflow.rb +52 -0
- data/lib/cadence/workflow/serializer/start_timer.rb +20 -0
- data/lib/cadence/workflow/state_manager.rb +324 -0
- data/lib/gen/thrift/cadence_constants.rb +11 -0
- data/lib/gen/thrift/cadence_types.rb +11 -0
- data/lib/gen/thrift/shared_constants.rb +11 -0
- data/lib/gen/thrift/shared_types.rb +4600 -0
- data/lib/gen/thrift/workflow_service.rb +3142 -0
- data/rbi/cadence-ruby.rbi +39 -0
- metadata +152 -5
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cadence/workflow/serializer/base'
|
2
|
+
|
3
|
+
module Cadence
|
4
|
+
class Workflow
|
5
|
+
module Serializer
|
6
|
+
class RequestActivityCancellation < Base
|
7
|
+
def to_thrift
|
8
|
+
CadenceThrift::Decision.new(
|
9
|
+
decisionType: CadenceThrift::DecisionType::RequestCancelActivityTask,
|
10
|
+
requestCancelActivityTaskDecisionAttributes:
|
11
|
+
CadenceThrift::RequestCancelActivityTaskDecisionAttributes.new(
|
12
|
+
activityId: object.activity_id.to_s
|
13
|
+
)
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'cadence/workflow/serializer/base'
|
2
|
+
require 'cadence/json'
|
3
|
+
|
4
|
+
module Cadence
|
5
|
+
class Workflow
|
6
|
+
module Serializer
|
7
|
+
class ScheduleActivity < Base
|
8
|
+
def to_thrift
|
9
|
+
CadenceThrift::Decision.new(
|
10
|
+
decisionType: CadenceThrift::DecisionType::ScheduleActivityTask,
|
11
|
+
scheduleActivityTaskDecisionAttributes:
|
12
|
+
CadenceThrift::ScheduleActivityTaskDecisionAttributes.new(
|
13
|
+
activityId: object.activity_id.to_s,
|
14
|
+
activityType: CadenceThrift::ActivityType.new(name: object.activity_type),
|
15
|
+
input: JSON.serialize(object.input),
|
16
|
+
domain: object.domain,
|
17
|
+
taskList: CadenceThrift::TaskList.new(name: object.task_list),
|
18
|
+
scheduleToCloseTimeoutSeconds: object.timeouts[:schedule_to_close],
|
19
|
+
scheduleToStartTimeoutSeconds: object.timeouts[:schedule_to_start],
|
20
|
+
startToCloseTimeoutSeconds: object.timeouts[:start_to_close],
|
21
|
+
heartbeatTimeoutSeconds: object.timeouts[:heartbeat],
|
22
|
+
retryPolicy: serialize_retry_policy(object.retry_policy),
|
23
|
+
header: serialize_headers(object.headers)
|
24
|
+
)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def serialize_retry_policy(retry_policy)
|
31
|
+
return unless retry_policy
|
32
|
+
|
33
|
+
non_retriable_errors = Array(retry_policy.non_retriable_errors).map(&:name)
|
34
|
+
options = {
|
35
|
+
initialIntervalInSeconds: retry_policy.interval,
|
36
|
+
backoffCoefficient: retry_policy.backoff,
|
37
|
+
maximumIntervalInSeconds: retry_policy.max_interval,
|
38
|
+
maximumAttempts: retry_policy.max_attempts,
|
39
|
+
nonRetriableErrorReasons: non_retriable_errors,
|
40
|
+
expirationIntervalInSeconds: retry_policy.expiration_interval
|
41
|
+
}.compact
|
42
|
+
|
43
|
+
CadenceThrift::RetryPolicy.new(options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def serialize_headers(headers)
|
47
|
+
return unless headers
|
48
|
+
|
49
|
+
CadenceThrift::Header.new(fields: object.headers)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'cadence/workflow/serializer/base'
|
2
|
+
require 'cadence/json'
|
3
|
+
|
4
|
+
module Cadence
|
5
|
+
class Workflow
|
6
|
+
module Serializer
|
7
|
+
class StartChildWorkflow < Base
|
8
|
+
def to_thrift
|
9
|
+
CadenceThrift::Decision.new(
|
10
|
+
decisionType: CadenceThrift::DecisionType::StartChildWorkflowExecution,
|
11
|
+
startChildWorkflowExecutionDecisionAttributes:
|
12
|
+
CadenceThrift::StartChildWorkflowExecutionDecisionAttributes.new(
|
13
|
+
domain: object.domain,
|
14
|
+
workflowId: object.workflow_id.to_s,
|
15
|
+
workflowType: CadenceThrift::WorkflowType.new(name: object.workflow_type),
|
16
|
+
taskList: CadenceThrift::TaskList.new(name: object.task_list),
|
17
|
+
input: JSON.serialize(object.input),
|
18
|
+
executionStartToCloseTimeoutSeconds: object.timeouts[:execution],
|
19
|
+
taskStartToCloseTimeoutSeconds: object.timeouts[:task],
|
20
|
+
retryPolicy: serialize_retry_policy(object.retry_policy),
|
21
|
+
header: serialize_headers(object.headers)
|
22
|
+
)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def serialize_retry_policy(retry_policy)
|
29
|
+
return unless retry_policy
|
30
|
+
|
31
|
+
non_retriable_errors = Array(retry_policy.non_retriable_errors).map(&:name)
|
32
|
+
options = {
|
33
|
+
initialIntervalInSeconds: retry_policy.interval,
|
34
|
+
backoffCoefficient: retry_policy.backoff,
|
35
|
+
maximumIntervalInSeconds: retry_policy.max_interval,
|
36
|
+
maximumAttempts: retry_policy.max_attempts,
|
37
|
+
nonRetriableErrorReasons: non_retriable_errors,
|
38
|
+
expirationIntervalInSeconds: retry_policy.expiration_interval
|
39
|
+
}.compact
|
40
|
+
|
41
|
+
CadenceThrift::RetryPolicy.new(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def serialize_headers(headers)
|
45
|
+
return unless headers
|
46
|
+
|
47
|
+
CadenceThrift::Header.new(fields: object.headers)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'cadence/workflow/serializer/base'
|
2
|
+
|
3
|
+
module Cadence
|
4
|
+
class Workflow
|
5
|
+
module Serializer
|
6
|
+
class StartTimer < Base
|
7
|
+
def to_thrift
|
8
|
+
CadenceThrift::Decision.new(
|
9
|
+
decisionType: CadenceThrift::DecisionType::StartTimer,
|
10
|
+
startTimerDecisionAttributes:
|
11
|
+
CadenceThrift::StartTimerDecisionAttributes.new(
|
12
|
+
timerId: object.timer_id.to_s,
|
13
|
+
startToFireTimeoutSeconds: object.timeout.to_i
|
14
|
+
)
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'cadence/json'
|
2
|
+
require 'cadence/errors'
|
3
|
+
require 'cadence/workflow/decision'
|
4
|
+
require 'cadence/workflow/decision_state_machine'
|
5
|
+
require 'cadence/workflow/history/event_target'
|
6
|
+
require 'cadence/metadata'
|
7
|
+
|
8
|
+
module Cadence
|
9
|
+
class Workflow
|
10
|
+
class StateManager
|
11
|
+
SIDE_EFFECT_MARKER = 'SIDE_EFFECT'.freeze
|
12
|
+
RELEASE_MARKER = 'RELEASE'.freeze
|
13
|
+
|
14
|
+
class UnsupportedEvent < Cadence::InternalError; end
|
15
|
+
class UnsupportedMarkerType < Cadence::InternalError; end
|
16
|
+
|
17
|
+
attr_reader :decisions, :local_time
|
18
|
+
|
19
|
+
def initialize(dispatcher)
|
20
|
+
@dispatcher = dispatcher
|
21
|
+
@decisions = []
|
22
|
+
@marker_ids = Set.new
|
23
|
+
@releases = {}
|
24
|
+
@side_effects = []
|
25
|
+
@decision_tracker = Hash.new { |hash, key| hash[key] = DecisionStateMachine.new }
|
26
|
+
@last_event_id = 0
|
27
|
+
@local_time = nil
|
28
|
+
@replay = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def replay?
|
32
|
+
@replay
|
33
|
+
end
|
34
|
+
|
35
|
+
def schedule(decision)
|
36
|
+
# Fast-forward event IDs to skip all the markers (version markers can
|
37
|
+
# be removed, so we can't rely on them being scheduled during a replay)
|
38
|
+
decision_id = next_event_id
|
39
|
+
while marker_ids.include?(decision_id) do
|
40
|
+
decision_id = next_event_id
|
41
|
+
end
|
42
|
+
|
43
|
+
cancelation_id =
|
44
|
+
case decision
|
45
|
+
when Decision::ScheduleActivity
|
46
|
+
decision.activity_id ||= decision_id
|
47
|
+
when Decision::StartChildWorkflow
|
48
|
+
decision.workflow_id ||= decision_id
|
49
|
+
when Decision::StartTimer
|
50
|
+
decision.timer_id ||= decision_id
|
51
|
+
end
|
52
|
+
|
53
|
+
state_machine = decision_tracker[decision_id]
|
54
|
+
state_machine.requested if state_machine.state == DecisionStateMachine::NEW_STATE
|
55
|
+
|
56
|
+
decisions << [decision_id, decision]
|
57
|
+
|
58
|
+
return [event_target_from(decision_id, decision), cancelation_id]
|
59
|
+
end
|
60
|
+
|
61
|
+
def release?(release_name)
|
62
|
+
track_release(release_name) unless releases.key?(release_name)
|
63
|
+
|
64
|
+
releases[release_name]
|
65
|
+
end
|
66
|
+
|
67
|
+
def next_side_effect
|
68
|
+
side_effects.shift
|
69
|
+
end
|
70
|
+
|
71
|
+
def apply(history_window)
|
72
|
+
@replay = history_window.replay?
|
73
|
+
@local_time = history_window.local_time
|
74
|
+
@last_event_id = history_window.last_event_id
|
75
|
+
|
76
|
+
# handle markers first since their data is needed for processing events
|
77
|
+
history_window.markers.each do |event|
|
78
|
+
apply_event(event)
|
79
|
+
end
|
80
|
+
|
81
|
+
history_window.events.each do |event|
|
82
|
+
apply_event(event)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
attr_reader :dispatcher, :decision_tracker, :marker_ids, :side_effects, :releases
|
89
|
+
|
90
|
+
def next_event_id
|
91
|
+
@last_event_id += 1
|
92
|
+
end
|
93
|
+
|
94
|
+
def apply_event(event)
|
95
|
+
state_machine = decision_tracker[event.decision_id]
|
96
|
+
target = History::EventTarget.from_event(event)
|
97
|
+
|
98
|
+
case event.type
|
99
|
+
when 'WorkflowExecutionStarted'
|
100
|
+
state_machine.start
|
101
|
+
dispatch(
|
102
|
+
History::EventTarget.workflow,
|
103
|
+
'started',
|
104
|
+
safe_parse(event.attributes.input),
|
105
|
+
Metadata.generate(Metadata::WORKFLOW_TYPE, event.attributes)
|
106
|
+
)
|
107
|
+
|
108
|
+
when 'WorkflowExecutionCompleted'
|
109
|
+
# todo
|
110
|
+
|
111
|
+
when 'WorkflowExecutionFailed'
|
112
|
+
# todo
|
113
|
+
|
114
|
+
when 'WorkflowExecutionTimedOut'
|
115
|
+
# todo
|
116
|
+
|
117
|
+
when 'DecisionTaskScheduled'
|
118
|
+
# todo
|
119
|
+
|
120
|
+
when 'DecisionTaskStarted'
|
121
|
+
# todo
|
122
|
+
|
123
|
+
when 'DecisionTaskCompleted'
|
124
|
+
# todo
|
125
|
+
|
126
|
+
when 'DecisionTaskTimedOut'
|
127
|
+
# todo
|
128
|
+
|
129
|
+
when 'DecisionTaskFailed'
|
130
|
+
# todo
|
131
|
+
|
132
|
+
when 'ActivityTaskScheduled'
|
133
|
+
state_machine.schedule
|
134
|
+
discard_decision(target)
|
135
|
+
|
136
|
+
when 'ActivityTaskStarted'
|
137
|
+
state_machine.start
|
138
|
+
|
139
|
+
when 'ActivityTaskCompleted'
|
140
|
+
state_machine.complete
|
141
|
+
dispatch(target, 'completed', safe_parse(event.attributes.result))
|
142
|
+
|
143
|
+
when 'ActivityTaskFailed'
|
144
|
+
state_machine.fail
|
145
|
+
dispatch(target, 'failed', event.attributes.reason, safe_parse(event.attributes.details))
|
146
|
+
|
147
|
+
when 'ActivityTaskTimedOut'
|
148
|
+
state_machine.time_out
|
149
|
+
type = CadenceThrift::TimeoutType::VALUE_MAP[event.attributes.timeoutType]
|
150
|
+
dispatch(target, 'failed', 'Cadence::TimeoutError', "Timeout type: #{type}")
|
151
|
+
|
152
|
+
when 'ActivityTaskCancelRequested'
|
153
|
+
state_machine.requested
|
154
|
+
discard_decision(target)
|
155
|
+
|
156
|
+
when 'RequestCancelActivityTaskFailed'
|
157
|
+
state_machine.fail
|
158
|
+
dispatch(target, 'failed', event.attributes.cause, nil)
|
159
|
+
|
160
|
+
when 'ActivityTaskCanceled'
|
161
|
+
state_machine.cancel
|
162
|
+
dispatch(target, 'failed', 'CANCELLED', safe_parse(event.attributes.details))
|
163
|
+
|
164
|
+
when 'TimerStarted'
|
165
|
+
state_machine.start
|
166
|
+
discard_decision(target)
|
167
|
+
|
168
|
+
when 'TimerFired'
|
169
|
+
state_machine.complete
|
170
|
+
dispatch(target, 'fired')
|
171
|
+
|
172
|
+
when 'CancelTimerFailed'
|
173
|
+
state_machine.failed
|
174
|
+
dispatch(target, 'failed', event.attributes.cause, nil)
|
175
|
+
|
176
|
+
when 'TimerCanceled'
|
177
|
+
state_machine.cancel
|
178
|
+
dispatch(target, 'canceled')
|
179
|
+
|
180
|
+
when 'WorkflowExecutionCancelRequested'
|
181
|
+
# todo
|
182
|
+
|
183
|
+
when 'WorkflowExecutionCanceled'
|
184
|
+
# todo
|
185
|
+
|
186
|
+
when 'RequestCancelExternalWorkflowExecutionInitiated'
|
187
|
+
# todo
|
188
|
+
|
189
|
+
when 'RequestCancelExternalWorkflowExecutionFailed'
|
190
|
+
# todo
|
191
|
+
|
192
|
+
when 'ExternalWorkflowExecutionCancelRequested'
|
193
|
+
# todo
|
194
|
+
|
195
|
+
when 'MarkerRecorded'
|
196
|
+
state_machine.complete
|
197
|
+
handle_marker(event.id, event.attributes.markerName, safe_parse(event.attributes.details))
|
198
|
+
|
199
|
+
when 'WorkflowExecutionSignaled'
|
200
|
+
dispatch(target, 'signaled', event.attributes.signalName, safe_parse(event.attributes.input))
|
201
|
+
|
202
|
+
when 'WorkflowExecutionTerminated'
|
203
|
+
# todo
|
204
|
+
|
205
|
+
when 'WorkflowExecutionContinuedAsNew'
|
206
|
+
# todo
|
207
|
+
|
208
|
+
when 'StartChildWorkflowExecutionInitiated'
|
209
|
+
state_machine.schedule
|
210
|
+
discard_decision(target)
|
211
|
+
|
212
|
+
when 'StartChildWorkflowExecutionFailed'
|
213
|
+
state_machine.fail
|
214
|
+
dispatch(target, 'failed', 'StandardError', safe_parse(event.attributes.cause))
|
215
|
+
|
216
|
+
when 'ChildWorkflowExecutionStarted'
|
217
|
+
state_machine.start
|
218
|
+
|
219
|
+
when 'ChildWorkflowExecutionCompleted'
|
220
|
+
state_machine.complete
|
221
|
+
dispatch(target, 'completed', safe_parse(event.attributes.result))
|
222
|
+
|
223
|
+
when 'ChildWorkflowExecutionFailed'
|
224
|
+
state_machine.fail
|
225
|
+
dispatch(target, 'failed', event.attributes.reason, safe_parse(event.attributes.details))
|
226
|
+
|
227
|
+
when 'ChildWorkflowExecutionCanceled'
|
228
|
+
state_machine.cancel
|
229
|
+
dispatch(target, 'failed', 'CANCELLED', safe_parse(event.attributes.details))
|
230
|
+
|
231
|
+
when 'ChildWorkflowExecutionTimedOut'
|
232
|
+
state_machine.time_out
|
233
|
+
type = CadenceThrift::TimeoutType::VALUE_MAP[event.attributes.timeoutType]
|
234
|
+
dispatch(target, 'failed', 'Cadence::TimeoutError', "Timeout type: #{type}")
|
235
|
+
|
236
|
+
when 'ChildWorkflowExecutionTerminated'
|
237
|
+
# todo
|
238
|
+
|
239
|
+
when 'SignalExternalWorkflowExecutionInitiated'
|
240
|
+
# todo
|
241
|
+
|
242
|
+
when 'SignalExternalWorkflowExecutionFailed'
|
243
|
+
# todo
|
244
|
+
|
245
|
+
when 'ExternalWorkflowExecutionSignaled'
|
246
|
+
# todo
|
247
|
+
|
248
|
+
when 'UpsertWorkflowSearchAttributes'
|
249
|
+
# todo
|
250
|
+
|
251
|
+
else
|
252
|
+
raise UnsupportedEvent, event.type
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def event_target_from(decision_id, decision)
|
257
|
+
target_type =
|
258
|
+
case decision
|
259
|
+
when Decision::ScheduleActivity
|
260
|
+
History::EventTarget::ACTIVITY_TYPE
|
261
|
+
when Decision::RequestActivityCancellation
|
262
|
+
History::EventTarget::CANCEL_ACTIVITY_REQUEST_TYPE
|
263
|
+
when Decision::RecordMarker
|
264
|
+
History::EventTarget::MARKER_TYPE
|
265
|
+
when Decision::StartTimer
|
266
|
+
History::EventTarget::TIMER_TYPE
|
267
|
+
when Decision::CancelTimer
|
268
|
+
History::EventTarget::CANCEL_TIMER_REQUEST_TYPE
|
269
|
+
when Decision::CompleteWorkflow, Decision::FailWorkflow
|
270
|
+
History::EventTarget::WORKFLOW_TYPE
|
271
|
+
when Decision::StartChildWorkflow
|
272
|
+
History::EventTarget::CHILD_WORKFLOW_TYPE
|
273
|
+
end
|
274
|
+
|
275
|
+
History::EventTarget.new(decision_id, target_type)
|
276
|
+
end
|
277
|
+
|
278
|
+
def dispatch(target, name, *attributes)
|
279
|
+
dispatcher.dispatch(target, name, attributes)
|
280
|
+
end
|
281
|
+
|
282
|
+
def discard_decision(target)
|
283
|
+
# Pop the first decision from the list, it is expected to match
|
284
|
+
existing_decision_id, existing_decision = decisions.shift
|
285
|
+
|
286
|
+
if !existing_decision_id
|
287
|
+
raise NonDeterministicWorkflowError, "A decision #{target} was not scheduled upon replay"
|
288
|
+
end
|
289
|
+
|
290
|
+
existing_target = event_target_from(existing_decision_id, existing_decision)
|
291
|
+
if target != existing_target
|
292
|
+
raise NonDeterministicWorkflowError, "Unexpected decision #{existing_target} (expected #{target})"
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def handle_marker(id, type, details)
|
297
|
+
marker_ids << id
|
298
|
+
|
299
|
+
case type
|
300
|
+
when SIDE_EFFECT_MARKER
|
301
|
+
side_effects << [id, details]
|
302
|
+
when RELEASE_MARKER
|
303
|
+
releases[details] = true
|
304
|
+
else
|
305
|
+
raise UnsupportedMarkerType, event.type
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def track_release(release_name)
|
310
|
+
# replay does not allow untracked (via marker) releases
|
311
|
+
if replay?
|
312
|
+
releases[release_name] = false
|
313
|
+
else
|
314
|
+
releases[release_name] = true
|
315
|
+
schedule(Decision::RecordMarker.new(name: RELEASE_MARKER, details: release_name))
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def safe_parse(binary)
|
320
|
+
JSON.deserialize(binary)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|