temporal-ruby 0.0.0 → 0.0.1.pre.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -42
- data/lib/gen/temporal/api/command/v1/message_pb.rb +146 -0
- data/lib/gen/temporal/api/common/v1/message_pb.rb +67 -0
- data/lib/gen/temporal/api/enums/v1/command_type_pb.rb +35 -0
- data/lib/gen/temporal/api/enums/v1/common_pb.rb +34 -0
- data/lib/gen/temporal/api/enums/v1/event_type_pb.rb +62 -0
- data/lib/gen/temporal/api/enums/v1/failed_cause_pb.rb +60 -0
- data/lib/gen/temporal/api/enums/v1/namespace_pb.rb +31 -0
- data/lib/gen/temporal/api/enums/v1/query_pb.rb +31 -0
- data/lib/gen/temporal/api/enums/v1/task_queue_pb.rb +30 -0
- data/lib/gen/temporal/api/enums/v1/workflow_pb.rb +82 -0
- data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +55 -0
- data/lib/gen/temporal/api/failure/v1/message_pb.rb +81 -0
- data/lib/gen/temporal/api/filter/v1/message_pb.rb +38 -0
- data/lib/gen/temporal/api/history/v1/message_pb.rb +423 -0
- data/lib/gen/temporal/api/namespace/v1/message_pb.rb +55 -0
- data/lib/gen/temporal/api/query/v1/message_pb.rb +36 -0
- data/lib/gen/temporal/api/replication/v1/message_pb.rb +27 -0
- data/lib/gen/temporal/api/taskqueue/v1/message_pb.rb +60 -0
- data/lib/gen/temporal/api/version/v1/message_pb.rb +28 -0
- data/lib/gen/temporal/api/workflow/v1/message_pb.rb +83 -0
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +538 -0
- data/lib/gen/temporal/api/workflowservice/v1/service_pb.rb +19 -0
- data/lib/gen/temporal/api/workflowservice/v1/service_services_pb.rb +223 -0
- data/lib/temporal-ruby.rb +1 -0
- data/lib/temporal.rb +137 -0
- data/lib/temporal/activity.rb +33 -0
- data/lib/temporal/activity/async_token.rb +34 -0
- data/lib/temporal/activity/context.rb +64 -0
- data/lib/temporal/activity/poller.rb +79 -0
- data/lib/temporal/activity/task_processor.rb +78 -0
- data/lib/temporal/activity/workflow_convenience_methods.rb +41 -0
- data/lib/temporal/client.rb +21 -0
- data/lib/temporal/client/errors.rb +8 -0
- data/lib/temporal/client/grpc_client.rb +345 -0
- data/lib/temporal/client/serializer.rb +31 -0
- data/lib/temporal/client/serializer/base.rb +23 -0
- data/lib/temporal/client/serializer/cancel_timer.rb +19 -0
- data/lib/temporal/client/serializer/complete_workflow.rb +20 -0
- data/lib/temporal/client/serializer/fail_workflow.rb +20 -0
- data/lib/temporal/client/serializer/failure.rb +29 -0
- data/lib/temporal/client/serializer/payload.rb +25 -0
- data/lib/temporal/client/serializer/record_marker.rb +23 -0
- data/lib/temporal/client/serializer/request_activity_cancellation.rb +19 -0
- data/lib/temporal/client/serializer/schedule_activity.rb +53 -0
- data/lib/temporal/client/serializer/start_child_workflow.rb +51 -0
- data/lib/temporal/client/serializer/start_timer.rb +20 -0
- data/lib/temporal/concerns/executable.rb +37 -0
- data/lib/temporal/concerns/typed.rb +40 -0
- data/lib/temporal/configuration.rb +44 -0
- data/lib/temporal/errors.rb +38 -0
- data/lib/temporal/executable_lookup.rb +25 -0
- data/lib/temporal/execution_options.rb +35 -0
- data/lib/temporal/json.rb +18 -0
- data/lib/temporal/metadata.rb +68 -0
- data/lib/temporal/metadata/activity.rb +27 -0
- data/lib/temporal/metadata/base.rb +17 -0
- data/lib/temporal/metadata/workflow.rb +22 -0
- data/lib/temporal/metadata/workflow_task.rb +25 -0
- data/lib/temporal/metrics.rb +37 -0
- data/lib/temporal/metrics_adapters/log.rb +33 -0
- data/lib/temporal/metrics_adapters/null.rb +9 -0
- data/lib/temporal/middleware/chain.rb +30 -0
- data/lib/temporal/middleware/entry.rb +9 -0
- data/lib/temporal/retry_policy.rb +27 -0
- data/lib/temporal/saga/concern.rb +23 -0
- data/lib/temporal/saga/result.rb +22 -0
- data/lib/temporal/saga/saga.rb +24 -0
- data/lib/temporal/testing.rb +50 -0
- data/lib/temporal/testing/future_registry.rb +27 -0
- data/lib/temporal/testing/local_activity_context.rb +17 -0
- data/lib/temporal/testing/local_workflow_context.rb +178 -0
- data/lib/temporal/testing/temporal_override.rb +121 -0
- data/lib/temporal/testing/workflow_execution.rb +44 -0
- data/lib/temporal/testing/workflow_override.rb +36 -0
- data/lib/temporal/thread_local_context.rb +14 -0
- data/lib/temporal/thread_pool.rb +63 -0
- data/lib/temporal/types.rb +7 -0
- data/lib/temporal/uuid.rb +19 -0
- data/lib/temporal/version.rb +1 -1
- data/lib/temporal/worker.rb +88 -0
- data/lib/temporal/workflow.rb +42 -0
- data/lib/temporal/workflow/command.rb +39 -0
- data/lib/temporal/workflow/command_state_machine.rb +48 -0
- data/lib/temporal/workflow/context.rb +243 -0
- data/lib/temporal/workflow/convenience_methods.rb +34 -0
- data/lib/temporal/workflow/dispatcher.rb +31 -0
- data/lib/temporal/workflow/execution_info.rb +51 -0
- data/lib/temporal/workflow/executor.rb +45 -0
- data/lib/temporal/workflow/future.rb +77 -0
- data/lib/temporal/workflow/history.rb +76 -0
- data/lib/temporal/workflow/history/event.rb +69 -0
- data/lib/temporal/workflow/history/event_target.rb +75 -0
- data/lib/temporal/workflow/history/window.rb +40 -0
- data/lib/temporal/workflow/poller.rb +67 -0
- data/lib/temporal/workflow/replay_aware_logger.rb +36 -0
- data/lib/temporal/workflow/state_manager.rb +342 -0
- data/lib/temporal/workflow/task_processor.rb +78 -0
- data/rbi/temporal-ruby.rbi +43 -0
- data/temporal.gemspec +10 -2
- metadata +186 -6
@@ -0,0 +1,40 @@
|
|
1
|
+
module Temporal
|
2
|
+
class Workflow
|
3
|
+
class History
|
4
|
+
class Window
|
5
|
+
attr_reader :local_time, :last_event_id, :events, :markers
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@local_time = nil
|
9
|
+
@last_event_id = nil
|
10
|
+
@events = []
|
11
|
+
@markers = []
|
12
|
+
@replay = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def replay?
|
16
|
+
@replay
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(event)
|
20
|
+
case event.type
|
21
|
+
when 'MARKER_RECORDED'
|
22
|
+
markers << event
|
23
|
+
when 'WORKFLOW_TASK_STARTED'
|
24
|
+
@last_event_id = event.id + 1 # one for completed
|
25
|
+
@local_time = event.timestamp
|
26
|
+
when 'WORKFLOW_TASK_FAILED', 'WORKFLOW_TASK_TIMED_OUT'
|
27
|
+
@last_event_id = nil
|
28
|
+
@local_time = nil
|
29
|
+
when 'WORKFLOW_TASK_COMPLETED'
|
30
|
+
@replay = true
|
31
|
+
when 'WORKFLOW_TASK_SCHEDULED', 'WORKFLOW_TASK_FAILED'
|
32
|
+
# no-op
|
33
|
+
else
|
34
|
+
events << event
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'temporal/client'
|
2
|
+
require 'temporal/middleware/chain'
|
3
|
+
require 'temporal/workflow/task_processor'
|
4
|
+
|
5
|
+
module Temporal
|
6
|
+
class Workflow
|
7
|
+
class Poller
|
8
|
+
def initialize(namespace, task_queue, workflow_lookup, middleware = [])
|
9
|
+
@namespace = namespace
|
10
|
+
@task_queue = task_queue
|
11
|
+
@workflow_lookup = workflow_lookup
|
12
|
+
@middleware = middleware
|
13
|
+
@shutting_down = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
@shutting_down = false
|
18
|
+
@thread = Thread.new(&method(:poll_loop))
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
@shutting_down = true
|
23
|
+
Thread.new { Temporal.logger.info('Shutting down a workflow poller') }.join
|
24
|
+
end
|
25
|
+
|
26
|
+
def wait
|
27
|
+
@thread.join
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :namespace, :task_queue, :client, :workflow_lookup, :middleware
|
33
|
+
|
34
|
+
def client
|
35
|
+
@client ||= Temporal::Client.generate
|
36
|
+
end
|
37
|
+
|
38
|
+
def middleware_chain
|
39
|
+
@middleware_chain ||= Middleware::Chain.new(middleware)
|
40
|
+
end
|
41
|
+
|
42
|
+
def shutting_down?
|
43
|
+
@shutting_down
|
44
|
+
end
|
45
|
+
|
46
|
+
def poll_loop
|
47
|
+
while !shutting_down? do
|
48
|
+
Temporal.logger.debug("Polling worklow task queue (#{namespace} / #{task_queue})")
|
49
|
+
|
50
|
+
task = poll_for_task
|
51
|
+
process(task) if task&.workflow_type
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def poll_for_task
|
56
|
+
client.poll_workflow_task_queue(namespace: namespace, task_queue: task_queue)
|
57
|
+
rescue StandardError => error
|
58
|
+
Temporal.logger.error("Unable to poll workflow task queue: #{error.inspect}")
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def process(task)
|
63
|
+
TaskProcessor.new(task, namespace, workflow_lookup, client, middleware_chain).process
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Temporal
|
2
|
+
class Workflow
|
3
|
+
class ReplayAwareLogger
|
4
|
+
SEVERITIES = %i[debug info warn error fatal unknown].freeze
|
5
|
+
|
6
|
+
attr_writer :replay
|
7
|
+
|
8
|
+
def initialize(main_logger, replay = true)
|
9
|
+
@main_logger = main_logger
|
10
|
+
@replay = replay
|
11
|
+
end
|
12
|
+
|
13
|
+
SEVERITIES.each do |severity|
|
14
|
+
define_method severity do |message|
|
15
|
+
return if replay?
|
16
|
+
|
17
|
+
main_logger.public_send(severity, message)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def log(severity, message)
|
22
|
+
return if replay?
|
23
|
+
|
24
|
+
main_logger.log(severity, message)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :main_logger
|
30
|
+
|
31
|
+
def replay?
|
32
|
+
@replay
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,342 @@
|
|
1
|
+
require 'temporal/json'
|
2
|
+
require 'temporal/errors'
|
3
|
+
require 'temporal/workflow/command'
|
4
|
+
require 'temporal/workflow/command_state_machine'
|
5
|
+
require 'temporal/workflow/history/event_target'
|
6
|
+
require 'temporal/metadata'
|
7
|
+
|
8
|
+
module Temporal
|
9
|
+
class Workflow
|
10
|
+
class StateManager
|
11
|
+
SIDE_EFFECT_MARKER = 'SIDE_EFFECT'.freeze
|
12
|
+
RELEASE_MARKER = 'RELEASE'.freeze
|
13
|
+
|
14
|
+
class UnsupportedEvent < Temporal::InternalError; end
|
15
|
+
class UnsupportedMarkerType < Temporal::InternalError; end
|
16
|
+
|
17
|
+
attr_reader :commands, :local_time
|
18
|
+
|
19
|
+
def initialize(dispatcher)
|
20
|
+
@dispatcher = dispatcher
|
21
|
+
@commands = []
|
22
|
+
@marker_ids = Set.new
|
23
|
+
@releases = {}
|
24
|
+
@side_effects = []
|
25
|
+
@command_tracker = Hash.new { |hash, key| hash[key] = CommandStateMachine.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(command)
|
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
|
+
command_id = next_event_id
|
39
|
+
while marker_ids.include?(command_id) do
|
40
|
+
command_id = next_event_id
|
41
|
+
end
|
42
|
+
|
43
|
+
cancelation_id =
|
44
|
+
case command
|
45
|
+
when Command::ScheduleActivity
|
46
|
+
command.activity_id ||= command_id
|
47
|
+
when Command::StartChildWorkflow
|
48
|
+
command.workflow_id ||= command_id
|
49
|
+
when Command::StartTimer
|
50
|
+
command.timer_id ||= command_id
|
51
|
+
end
|
52
|
+
|
53
|
+
state_machine = command_tracker[command_id]
|
54
|
+
state_machine.requested if state_machine.state == CommandStateMachine::NEW_STATE
|
55
|
+
|
56
|
+
commands << [command_id, command]
|
57
|
+
|
58
|
+
return [event_target_from(command_id, command), 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, :command_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 = command_tracker[event.originating_event_id]
|
96
|
+
target = History::EventTarget.from_event(event)
|
97
|
+
|
98
|
+
case event.type
|
99
|
+
when 'WORKFLOW_EXECUTION_STARTED'
|
100
|
+
state_machine.start
|
101
|
+
dispatch(
|
102
|
+
History::EventTarget.workflow,
|
103
|
+
'started',
|
104
|
+
parse_payload(event.attributes.input),
|
105
|
+
Metadata.generate(Metadata::WORKFLOW_TYPE, event.attributes)
|
106
|
+
)
|
107
|
+
|
108
|
+
when 'WORKFLOW_EXECUTION_COMPLETED'
|
109
|
+
# todo
|
110
|
+
|
111
|
+
when 'WORKFLOW_EXECUTION_FAILED'
|
112
|
+
# todo
|
113
|
+
|
114
|
+
when 'WORKFLOW_EXECUTION_TIMED_OUT'
|
115
|
+
# todo
|
116
|
+
|
117
|
+
when 'WORKFLOW_TASK_SCHEDULED'
|
118
|
+
# todo
|
119
|
+
|
120
|
+
when 'WORKFLOW_TASK_STARTED'
|
121
|
+
# todo
|
122
|
+
|
123
|
+
when 'WORKFLOW_TASK_COMPLETED'
|
124
|
+
# todo
|
125
|
+
|
126
|
+
when 'WORKFLOW_TASK_TIMED_OUT'
|
127
|
+
# todo
|
128
|
+
|
129
|
+
when 'WORKFLOW_TASK_FAILED'
|
130
|
+
# todo
|
131
|
+
|
132
|
+
when 'ACTIVITY_TASK_SCHEDULED'
|
133
|
+
state_machine.schedule
|
134
|
+
discard_command(event.originating_event_id)
|
135
|
+
|
136
|
+
when 'ACTIVITY_TASK_STARTED'
|
137
|
+
state_machine.start
|
138
|
+
|
139
|
+
when 'ACTIVITY_TASK_COMPLETED'
|
140
|
+
state_machine.complete
|
141
|
+
dispatch(target, 'completed', parse_payload(event.attributes.result))
|
142
|
+
|
143
|
+
when 'ACTIVITY_TASK_FAILED'
|
144
|
+
state_machine.fail
|
145
|
+
dispatch(target, 'failed', parse_failure(event.attributes.failure, ActivityException))
|
146
|
+
|
147
|
+
when 'ACTIVITY_TASK_TIMED_OUT'
|
148
|
+
state_machine.time_out
|
149
|
+
dispatch(target, 'failed', parse_failure(event.attributes.failure))
|
150
|
+
|
151
|
+
when 'ACTIVITY_TASK_CANCEL_REQUESTED'
|
152
|
+
state_machine.requested
|
153
|
+
discard_command(event.originating_event_id)
|
154
|
+
|
155
|
+
when 'REQUEST_CANCEL_ACTIVITY_TASK_FAILED'
|
156
|
+
state_machine.fail
|
157
|
+
dispatch(target, 'failed', event.attributes.cause, nil)
|
158
|
+
|
159
|
+
when 'ACTIVITY_TASK_CANCELED'
|
160
|
+
state_machine.cancel
|
161
|
+
dispatch(target, 'failed', parse_failure(event.attributes.failure))
|
162
|
+
|
163
|
+
when 'TIMER_STARTED'
|
164
|
+
state_machine.start
|
165
|
+
discard_command(event.originating_event_id)
|
166
|
+
|
167
|
+
when 'TIMER_FIRED'
|
168
|
+
state_machine.complete
|
169
|
+
dispatch(target, 'fired')
|
170
|
+
|
171
|
+
when 'CANCEL_TIMER_FAILED'
|
172
|
+
state_machine.failed
|
173
|
+
dispatch(target, 'failed', event.attributes.cause, nil)
|
174
|
+
|
175
|
+
when 'TIMER_CANCELED'
|
176
|
+
state_machine.cancel
|
177
|
+
dispatch(target, 'canceled')
|
178
|
+
|
179
|
+
when 'WORKFLOW_EXECUTION_CANCEL_REQUESTED'
|
180
|
+
# todo
|
181
|
+
|
182
|
+
when 'WORKFLOW_EXECUTION_CANCELED'
|
183
|
+
# todo
|
184
|
+
|
185
|
+
when 'REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED'
|
186
|
+
# todo
|
187
|
+
|
188
|
+
when 'REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED'
|
189
|
+
# todo
|
190
|
+
|
191
|
+
when 'EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED'
|
192
|
+
# todo
|
193
|
+
|
194
|
+
when 'MARKER_RECORDED'
|
195
|
+
state_machine.complete
|
196
|
+
handle_marker(event.id, event.attributes.marker_name, parse_payload(event.attributes.details['data']))
|
197
|
+
|
198
|
+
when 'WORKFLOW_EXECUTION_SIGNALED'
|
199
|
+
dispatch(target, 'signaled', event.attributes.signal_name, parse_payload(event.attributes.input))
|
200
|
+
|
201
|
+
when 'WORKFLOW_EXECUTION_TERMINATED'
|
202
|
+
# todo
|
203
|
+
|
204
|
+
when 'WORKFLOW_EXECUTION_CONTINUED_AS_NEW'
|
205
|
+
# todo
|
206
|
+
|
207
|
+
when 'START_CHILD_WORKFLOW_EXECUTION_INITIATED'
|
208
|
+
state_machine.schedule
|
209
|
+
discard_command(event.originating_event_id)
|
210
|
+
|
211
|
+
when 'START_CHILD_WORKFLOW_EXECUTION_FAILED'
|
212
|
+
state_machine.fail
|
213
|
+
dispatch(target, 'failed', 'StandardError', parse_payload(event.attributes.cause))
|
214
|
+
|
215
|
+
when 'CHILD_WORKFLOW_EXECUTION_STARTED'
|
216
|
+
state_machine.start
|
217
|
+
|
218
|
+
when 'CHILD_WORKFLOW_EXECUTION_COMPLETED'
|
219
|
+
state_machine.complete
|
220
|
+
dispatch(target, 'completed', parse_payload(event.attributes.result))
|
221
|
+
|
222
|
+
when 'CHILD_WORKFLOW_EXECUTION_FAILED'
|
223
|
+
state_machine.fail
|
224
|
+
dispatch(target, 'failed', parse_failure(event.attributes.failure))
|
225
|
+
|
226
|
+
when 'CHILD_WORKFLOW_EXECUTION_CANCELED'
|
227
|
+
state_machine.cancel
|
228
|
+
dispatch(target, 'failed', parse_failure(event.attributes.failure))
|
229
|
+
|
230
|
+
when 'CHILD_WORKFLOW_EXECUTION_TIMED_OUT'
|
231
|
+
state_machine.time_out
|
232
|
+
dispatch(target, 'failed', parse_failure(event.attributes.failure))
|
233
|
+
|
234
|
+
when 'CHILD_WORKFLOW_EXECUTION_TERMINATED'
|
235
|
+
# todo
|
236
|
+
|
237
|
+
when 'SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED'
|
238
|
+
# todo
|
239
|
+
|
240
|
+
when 'SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED'
|
241
|
+
# todo
|
242
|
+
|
243
|
+
when 'EXTERNAL_WORKFLOW_EXECUTION_SIGNALED'
|
244
|
+
# todo
|
245
|
+
|
246
|
+
when 'UPSERT_WORKFLOW_SEARCH_ATTRIBUTES'
|
247
|
+
# todo
|
248
|
+
|
249
|
+
else
|
250
|
+
raise UnsupportedEvent, event.type
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def event_target_from(command_id, command)
|
255
|
+
target_type =
|
256
|
+
case command
|
257
|
+
when Command::ScheduleActivity
|
258
|
+
History::EventTarget::ACTIVITY_TYPE
|
259
|
+
when Command::RequestActivityCancellation
|
260
|
+
History::EventTarget::CANCEL_ACTIVITY_REQUEST_TYPE
|
261
|
+
when Command::RecordMarker
|
262
|
+
History::EventTarget::MARKER_TYPE
|
263
|
+
when Command::StartTimer
|
264
|
+
History::EventTarget::TIMER_TYPE
|
265
|
+
when Command::CancelTimer
|
266
|
+
History::EventTarget::CANCEL_TIMER_REQUEST_TYPE
|
267
|
+
when Command::CompleteWorkflow, Command::FailWorkflow
|
268
|
+
History::EventTarget::WORKFLOW_TYPE
|
269
|
+
when Command::StartChildWorkflow
|
270
|
+
History::EventTarget::CHILD_WORKFLOW_TYPE
|
271
|
+
end
|
272
|
+
|
273
|
+
History::EventTarget.new(command_id, target_type)
|
274
|
+
end
|
275
|
+
|
276
|
+
def dispatch(target, name, *attributes)
|
277
|
+
dispatcher.dispatch(target, name, attributes)
|
278
|
+
end
|
279
|
+
|
280
|
+
def discard_command(command_id)
|
281
|
+
commands.delete_if { |(id, _)| id == command_id }
|
282
|
+
end
|
283
|
+
|
284
|
+
def handle_marker(id, type, details)
|
285
|
+
marker_ids << id
|
286
|
+
|
287
|
+
case type
|
288
|
+
when SIDE_EFFECT_MARKER
|
289
|
+
side_effects << [id, details]
|
290
|
+
when RELEASE_MARKER
|
291
|
+
releases[details] = true
|
292
|
+
else
|
293
|
+
raise UnsupportedMarkerType, event.type
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def track_release(release_name)
|
298
|
+
# replay does not allow untracked (via marker) releases
|
299
|
+
if replay?
|
300
|
+
releases[release_name] = false
|
301
|
+
else
|
302
|
+
releases[release_name] = true
|
303
|
+
schedule(Command::RecordMarker.new(name: RELEASE_MARKER, details: release_name))
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def parse_payload(payload)
|
308
|
+
return if payload.nil? || payload.payloads.empty?
|
309
|
+
|
310
|
+
binary = payload.payloads.first.data
|
311
|
+
JSON.deserialize(binary)
|
312
|
+
end
|
313
|
+
|
314
|
+
def parse_failure(failure, default_exception_class = StandardError)
|
315
|
+
case failure.failure_info
|
316
|
+
when :application_failure_info
|
317
|
+
exception_class = safe_constantize(failure.application_failure_info.type)
|
318
|
+
exception_class ||= default_exception_class
|
319
|
+
details = parse_payload(failure.application_failure_info.details)
|
320
|
+
backtrace = failure.stack_trace.split("\n")
|
321
|
+
|
322
|
+
exception_class.new(details).tap do |exception|
|
323
|
+
exception.set_backtrace(backtrace) if !backtrace.empty?
|
324
|
+
end
|
325
|
+
when :timeout_failure_info
|
326
|
+
TimeoutError.new("Timeout type: #{failure.timeout_failure_info.timeout_type.to_s}")
|
327
|
+
when :canceled_failure_info
|
328
|
+
# TODO: Distinguish between different entity cancellations
|
329
|
+
StandardError.new(parse_payload(failure.canceled_failure_info.details))
|
330
|
+
else
|
331
|
+
StandardError.new(failure.message)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def safe_constantize(const)
|
336
|
+
Object.const_get(const) if Object.const_defined?(const)
|
337
|
+
rescue NameError
|
338
|
+
nil
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|