temporal-ruby 0.0.1.pre.pre1 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/README.md +23 -3
- data/lib/gen/temporal/api/command/v1/message_pb.rb +1 -1
- data/lib/gen/temporal/api/enums/v1/common_pb.rb +7 -0
- data/lib/gen/temporal/api/errordetails/v1/message_pb.rb +5 -6
- data/lib/gen/temporal/api/version/v1/message_pb.rb +19 -8
- data/lib/gen/temporal/api/workflowservice/v1/request_response_pb.rb +19 -8
- data/lib/gen/temporal/api/workflowservice/v1/service_services_pb.rb +0 -3
- data/lib/temporal.rb +104 -0
- data/lib/temporal/activity/context.rb +5 -1
- data/lib/temporal/activity/poller.rb +26 -9
- data/lib/temporal/activity/task_processor.rb +33 -20
- data/lib/temporal/client/converter/base.rb +35 -0
- data/lib/temporal/client/converter/composite.rb +49 -0
- data/lib/temporal/client/converter/payload/bytes.rb +30 -0
- data/lib/temporal/client/converter/payload/json.rb +28 -0
- data/lib/temporal/client/converter/payload/nil.rb +27 -0
- data/lib/temporal/client/grpc_client.rb +102 -27
- data/lib/temporal/client/retryer.rb +49 -0
- data/lib/temporal/client/serializer.rb +2 -0
- data/lib/temporal/client/serializer/cancel_timer.rb +2 -2
- data/lib/temporal/client/serializer/complete_workflow.rb +6 -4
- data/lib/temporal/client/serializer/continue_as_new.rb +37 -0
- data/lib/temporal/client/serializer/fail_workflow.rb +2 -2
- data/lib/temporal/client/serializer/failure.rb +4 -2
- data/lib/temporal/client/serializer/record_marker.rb +6 -4
- data/lib/temporal/client/serializer/request_activity_cancellation.rb +2 -2
- data/lib/temporal/client/serializer/retry_policy.rb +24 -0
- data/lib/temporal/client/serializer/schedule_activity.rb +8 -20
- data/lib/temporal/client/serializer/start_child_workflow.rb +9 -20
- data/lib/temporal/client/serializer/start_timer.rb +2 -2
- data/lib/temporal/concerns/payloads.rb +51 -0
- data/lib/temporal/configuration.rb +31 -4
- data/lib/temporal/error_handler.rb +11 -0
- data/lib/temporal/errors.rb +24 -0
- data/lib/temporal/execution_options.rb +9 -1
- data/lib/temporal/json.rb +3 -1
- data/lib/temporal/logger.rb +17 -0
- data/lib/temporal/metadata.rb +11 -3
- data/lib/temporal/metadata/activity.rb +15 -2
- data/lib/temporal/metadata/workflow.rb +8 -0
- data/lib/temporal/metadata/workflow_task.rb +11 -0
- data/lib/temporal/retry_policy.rb +6 -9
- data/lib/temporal/saga/concern.rb +1 -1
- data/lib/temporal/testing.rb +1 -0
- data/lib/temporal/testing/future_registry.rb +1 -1
- data/lib/temporal/testing/local_activity_context.rb +1 -1
- data/lib/temporal/testing/local_workflow_context.rb +38 -14
- data/lib/temporal/testing/scheduled_workflows.rb +75 -0
- data/lib/temporal/testing/temporal_override.rb +35 -7
- data/lib/temporal/testing/workflow_override.rb +6 -1
- data/lib/temporal/version.rb +1 -1
- data/lib/temporal/worker.rb +28 -10
- data/lib/temporal/workflow.rb +8 -2
- data/lib/temporal/workflow/command.rb +3 -0
- data/lib/temporal/workflow/context.rb +40 -5
- data/lib/temporal/workflow/errors.rb +39 -0
- data/lib/temporal/workflow/executor.rb +1 -1
- data/lib/temporal/workflow/future.rb +18 -6
- data/lib/temporal/workflow/history/event.rb +1 -3
- data/lib/temporal/workflow/history/event_target.rb +4 -0
- data/lib/temporal/workflow/history/window.rb +1 -1
- data/lib/temporal/workflow/poller.rb +41 -13
- data/lib/temporal/workflow/replay_aware_logger.rb +4 -4
- data/lib/temporal/workflow/state_manager.rb +33 -52
- data/lib/temporal/workflow/task_processor.rb +41 -11
- metadata +21 -9
- data/lib/temporal/client/serializer/payload.rb +0 -25
@@ -7,11 +7,25 @@ require 'temporal/testing/local_workflow_context'
|
|
7
7
|
module Temporal
|
8
8
|
module Testing
|
9
9
|
module TemporalOverride
|
10
|
+
|
10
11
|
def start_workflow(workflow, *input, **args)
|
11
12
|
return super if Temporal::Testing.disabled?
|
12
13
|
|
13
14
|
if Temporal::Testing.local?
|
14
|
-
start_locally(workflow, *input, **args)
|
15
|
+
start_locally(workflow, nil, *input, **args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# We don't support testing the actual cron schedules, but we will defer
|
20
|
+
# execution. You can simulate running these deferred with
|
21
|
+
# Temporal::Testing.execute_all_scheduled_workflows o
|
22
|
+
# Temporal::Testing.execute_scheduled_workflow, or assert against the cron schedule with
|
23
|
+
# Temporal::Testing.schedules.
|
24
|
+
def schedule_workflow(workflow, cron_schedule, *input, **args)
|
25
|
+
return super if Temporal::Testing.disabled?
|
26
|
+
|
27
|
+
if Temporal::Testing.local?
|
28
|
+
start_locally(workflow, cron_schedule, *input, **args)
|
15
29
|
end
|
16
30
|
end
|
17
31
|
|
@@ -55,7 +69,7 @@ module Temporal
|
|
55
69
|
@executions ||= {}
|
56
70
|
end
|
57
71
|
|
58
|
-
def start_locally(workflow, *input, **args)
|
72
|
+
def start_locally(workflow, schedule, *input, **args)
|
59
73
|
options = args.delete(:options) || {}
|
60
74
|
input << args unless args.empty?
|
61
75
|
|
@@ -74,15 +88,29 @@ module Temporal
|
|
74
88
|
executions[[workflow_id, run_id]] = execution
|
75
89
|
|
76
90
|
execution_options = ExecutionOptions.new(workflow, options)
|
77
|
-
|
91
|
+
metadata = Metadata::Workflow.new(
|
92
|
+
name: workflow_id, run_id: run_id, attempt: 1, headers: execution_options.headers
|
93
|
+
)
|
78
94
|
context = Temporal::Testing::LocalWorkflowContext.new(
|
79
|
-
execution, workflow_id, run_id, workflow.disabled_releases,
|
95
|
+
execution, workflow_id, run_id, workflow.disabled_releases, metadata
|
80
96
|
)
|
81
97
|
|
82
|
-
|
83
|
-
|
98
|
+
if schedule.nil?
|
99
|
+
execution.run do
|
100
|
+
workflow.execute_in_context(context, input)
|
101
|
+
end
|
102
|
+
else
|
103
|
+
# Defer execution; in testing mode, it'll need to be invoked manually.
|
104
|
+
Temporal::Testing::ScheduledWorkflows::Private::Store.add(
|
105
|
+
workflow_id: workflow_id,
|
106
|
+
cron_schedule: schedule,
|
107
|
+
executor_lambda: lambda do
|
108
|
+
execution.run do
|
109
|
+
workflow.execute_in_context(context, input)
|
110
|
+
end
|
111
|
+
end,
|
112
|
+
)
|
84
113
|
end
|
85
|
-
|
86
114
|
run_id
|
87
115
|
end
|
88
116
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'securerandom'
|
2
|
+
require 'set'
|
2
3
|
require 'temporal/testing/local_workflow_context'
|
3
4
|
require 'temporal/testing/workflow_execution'
|
5
|
+
require 'temporal/metadata/workflow'
|
4
6
|
|
5
7
|
module Temporal
|
6
8
|
module Testing
|
@@ -25,8 +27,11 @@ module Temporal
|
|
25
27
|
workflow_id = SecureRandom.uuid
|
26
28
|
run_id = SecureRandom.uuid
|
27
29
|
execution = WorkflowExecution.new
|
30
|
+
metadata = Temporal::Metadata::Workflow.new(
|
31
|
+
name: workflow_id, run_id: run_id, attempt: 1
|
32
|
+
)
|
28
33
|
context = Temporal::Testing::LocalWorkflowContext.new(
|
29
|
-
execution, workflow_id, run_id, disabled_releases
|
34
|
+
execution, workflow_id, run_id, disabled_releases, metadata
|
30
35
|
)
|
31
36
|
|
32
37
|
execute_in_context(context, input)
|
data/lib/temporal/version.rb
CHANGED
data/lib/temporal/worker.rb
CHANGED
@@ -7,13 +7,24 @@ require 'temporal/middleware/entry'
|
|
7
7
|
|
8
8
|
module Temporal
|
9
9
|
class Worker
|
10
|
-
|
10
|
+
# activity_thread_pool_size: number of threads that the poller can use to run activities.
|
11
|
+
# can be set to 1 if you want no paralellism in your activities, at the cost of throughput.
|
12
|
+
def initialize(
|
13
|
+
activity_thread_pool_size: Temporal::Activity::Poller::DEFAULT_OPTIONS[:thread_pool_size],
|
14
|
+
workflow_thread_pool_size: Temporal::Workflow::Poller::DEFAULT_OPTIONS[:thread_pool_size]
|
15
|
+
)
|
11
16
|
@workflows = Hash.new { |hash, key| hash[key] = ExecutableLookup.new }
|
12
17
|
@activities = Hash.new { |hash, key| hash[key] = ExecutableLookup.new }
|
13
18
|
@pollers = []
|
14
19
|
@workflow_task_middleware = []
|
15
20
|
@activity_middleware = []
|
16
21
|
@shutting_down = false
|
22
|
+
@activity_poller_options = {
|
23
|
+
thread_pool_size: activity_thread_pool_size,
|
24
|
+
}
|
25
|
+
@workflow_poller_options = {
|
26
|
+
thread_pool_size: workflow_thread_pool_size,
|
27
|
+
}
|
17
28
|
end
|
18
29
|
|
19
30
|
def register_workflow(workflow_class, options = {})
|
@@ -51,32 +62,39 @@ module Temporal
|
|
51
62
|
|
52
63
|
pollers.each(&:start)
|
53
64
|
|
54
|
-
#
|
55
|
-
while !shutting_down?
|
56
|
-
sleep 1
|
57
|
-
end
|
65
|
+
# keep the main thread alive
|
66
|
+
sleep 1 while !shutting_down?
|
58
67
|
end
|
59
68
|
|
60
69
|
def stop
|
61
70
|
@shutting_down = true
|
62
|
-
|
63
|
-
|
71
|
+
|
72
|
+
Thread.new do
|
73
|
+
pollers.each(&:stop_polling)
|
74
|
+
# allow workers to drain in-transit tasks.
|
75
|
+
# https://github.com/temporalio/temporal/issues/1058
|
76
|
+
sleep 1
|
77
|
+
pollers.each(&:cancel_pending_requests)
|
78
|
+
pollers.each(&:wait)
|
79
|
+
end.join
|
64
80
|
end
|
65
81
|
|
66
82
|
private
|
67
83
|
|
68
|
-
attr_reader :
|
84
|
+
attr_reader :activity_poller_options, :workflow_poller_options,
|
85
|
+
:activities, :workflows, :pollers,
|
86
|
+
:workflow_task_middleware, :activity_middleware
|
69
87
|
|
70
88
|
def shutting_down?
|
71
89
|
@shutting_down
|
72
90
|
end
|
73
91
|
|
74
92
|
def workflow_poller_for(namespace, task_queue, lookup)
|
75
|
-
Workflow::Poller.new(namespace, task_queue, lookup.freeze, workflow_task_middleware)
|
93
|
+
Workflow::Poller.new(namespace, task_queue, lookup.freeze, workflow_task_middleware, workflow_poller_options)
|
76
94
|
end
|
77
95
|
|
78
96
|
def activity_poller_for(namespace, task_queue, lookup)
|
79
|
-
Activity::Poller.new(namespace, task_queue, lookup.freeze, activity_middleware)
|
97
|
+
Activity::Poller.new(namespace, task_queue, lookup.freeze, activity_middleware, activity_poller_options)
|
80
98
|
end
|
81
99
|
|
82
100
|
def trap_signals
|
data/lib/temporal/workflow.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'temporal/concerns/executable'
|
2
2
|
require 'temporal/workflow/convenience_methods'
|
3
3
|
require 'temporal/thread_local_context'
|
4
|
+
require 'temporal/error_handler'
|
4
5
|
|
5
6
|
module Temporal
|
6
7
|
class Workflow
|
@@ -8,17 +9,22 @@ module Temporal
|
|
8
9
|
extend ConvenienceMethods
|
9
10
|
|
10
11
|
def self.execute_in_context(context, input)
|
12
|
+
old_context = Temporal::ThreadLocalContext.get
|
11
13
|
Temporal::ThreadLocalContext.set(context)
|
12
14
|
|
13
15
|
workflow = new(context)
|
14
16
|
result = workflow.execute(*input)
|
15
17
|
|
16
|
-
context.complete(result)
|
18
|
+
context.complete(result) unless context.completed?
|
17
19
|
rescue StandardError, ScriptError => error
|
18
|
-
Temporal.logger.error("Workflow execution failed
|
20
|
+
Temporal.logger.error("Workflow execution failed", context.metadata.to_h.merge(error: error.inspect))
|
19
21
|
Temporal.logger.debug(error.backtrace.join("\n"))
|
20
22
|
|
23
|
+
Temporal::ErrorHandler.handle(error, metadata: context.metadata)
|
24
|
+
|
21
25
|
context.fail(error)
|
26
|
+
ensure
|
27
|
+
Temporal::ThreadLocalContext.set(old_context)
|
22
28
|
end
|
23
29
|
|
24
30
|
def initialize(context)
|
@@ -4,6 +4,7 @@ module Temporal
|
|
4
4
|
# TODO: Move these classes into their own directories under workflow/command/*
|
5
5
|
ScheduleActivity = Struct.new(:activity_type, :activity_id, :input, :namespace, :task_queue, :retry_policy, :timeouts, :headers, keyword_init: true)
|
6
6
|
StartChildWorkflow = Struct.new(:workflow_type, :workflow_id, :input, :namespace, :task_queue, :retry_policy, :timeouts, :headers, keyword_init: true)
|
7
|
+
ContinueAsNew = Struct.new(:workflow_type, :task_queue, :input, :timeouts, :retry_policy, :headers, keyword_init: true)
|
7
8
|
RequestActivityCancellation = Struct.new(:activity_id, keyword_init: true)
|
8
9
|
RecordMarker = Struct.new(:name, :details, keyword_init: true)
|
9
10
|
StartTimer = Struct.new(:timeout, :timer_id, keyword_init: true)
|
@@ -14,6 +15,7 @@ module Temporal
|
|
14
15
|
# only these commands are supported right now
|
15
16
|
SCHEDULE_ACTIVITY_TYPE = :schedule_activity
|
16
17
|
START_CHILD_WORKFLOW_TYPE = :start_child_workflow
|
18
|
+
CONTINUE_AS_NEW = :continue_as_new
|
17
19
|
RECORD_MARKER_TYPE = :record_marker
|
18
20
|
START_TIMER_TYPE = :start_timer
|
19
21
|
CANCEL_TIMER_TYPE = :cancel_timer
|
@@ -23,6 +25,7 @@ module Temporal
|
|
23
25
|
COMMAND_CLASS_MAP = {
|
24
26
|
SCHEDULE_ACTIVITY_TYPE => ScheduleActivity,
|
25
27
|
START_CHILD_WORKFLOW_TYPE => StartChildWorkflow,
|
28
|
+
CONTINUE_AS_NEW => ContinueAsNew,
|
26
29
|
RECORD_MARKER_TYPE => RecordMarker,
|
27
30
|
START_TIMER_TYPE => StartTimer,
|
28
31
|
CANCEL_TIMER_TYPE => CancelTimer,
|
@@ -15,10 +15,18 @@ require 'temporal/workflow/state_manager'
|
|
15
15
|
module Temporal
|
16
16
|
class Workflow
|
17
17
|
class Context
|
18
|
-
|
18
|
+
attr_reader :metadata
|
19
|
+
|
20
|
+
def initialize(state_manager, dispatcher, workflow_class, metadata)
|
19
21
|
@state_manager = state_manager
|
20
22
|
@dispatcher = dispatcher
|
23
|
+
@workflow_class = workflow_class
|
21
24
|
@metadata = metadata
|
25
|
+
@completed = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def completed?
|
29
|
+
@completed
|
22
30
|
end
|
23
31
|
|
24
32
|
def logger
|
@@ -57,11 +65,12 @@ module Temporal
|
|
57
65
|
|
58
66
|
dispatcher.register_handler(target, 'completed') do |result|
|
59
67
|
future.set(result)
|
60
|
-
future.
|
68
|
+
future.success_callbacks.each { |callback| call_in_fiber(callback, result) }
|
61
69
|
end
|
62
70
|
|
63
71
|
dispatcher.register_handler(target, 'failed') do |exception|
|
64
72
|
future.fail(exception)
|
73
|
+
future.failure_callbacks.each { |callback| call_in_fiber(callback, exception) }
|
65
74
|
end
|
66
75
|
|
67
76
|
future
|
@@ -109,11 +118,12 @@ module Temporal
|
|
109
118
|
|
110
119
|
dispatcher.register_handler(target, 'completed') do |result|
|
111
120
|
future.set(result)
|
112
|
-
future.
|
121
|
+
future.success_callbacks.each { |callback| call_in_fiber(callback, result) }
|
113
122
|
end
|
114
123
|
|
115
124
|
dispatcher.register_handler(target, 'failed') do |exception|
|
116
125
|
future.fail(exception)
|
126
|
+
future.failure_callbacks.each { |callback| call_in_fiber(callback, exception) }
|
117
127
|
end
|
118
128
|
|
119
129
|
future
|
@@ -150,11 +160,12 @@ module Temporal
|
|
150
160
|
|
151
161
|
dispatcher.register_handler(target, 'fired') do |result|
|
152
162
|
future.set(result)
|
153
|
-
future.
|
163
|
+
future.success_callbacks.each { |callback| call_in_fiber(callback, result) }
|
154
164
|
end
|
155
165
|
|
156
166
|
dispatcher.register_handler(target, 'canceled') do |exception|
|
157
167
|
future.fail(exception)
|
168
|
+
future.failure_callbacks.each { |callback| call_in_fiber(callback, exception) }
|
158
169
|
end
|
159
170
|
|
160
171
|
future
|
@@ -169,12 +180,32 @@ module Temporal
|
|
169
180
|
def complete(result = nil)
|
170
181
|
command = Command::CompleteWorkflow.new(result: result)
|
171
182
|
schedule_command(command)
|
183
|
+
completed!
|
172
184
|
end
|
173
185
|
|
174
186
|
# TODO: check if workflow can be failed
|
175
187
|
def fail(exception)
|
176
188
|
command = Command::FailWorkflow.new(exception: exception)
|
177
189
|
schedule_command(command)
|
190
|
+
completed!
|
191
|
+
end
|
192
|
+
|
193
|
+
def continue_as_new(*input, **args)
|
194
|
+
options = args.delete(:options) || {}
|
195
|
+
input << args unless args.empty?
|
196
|
+
|
197
|
+
execution_options = ExecutionOptions.new(workflow_class, options)
|
198
|
+
|
199
|
+
command = Command::ContinueAsNew.new(
|
200
|
+
workflow_type: execution_options.name,
|
201
|
+
task_queue: execution_options.task_queue,
|
202
|
+
input: input,
|
203
|
+
timeouts: execution_options.timeouts,
|
204
|
+
retry_policy: execution_options.retry_policy,
|
205
|
+
headers: execution_options.headers
|
206
|
+
)
|
207
|
+
schedule_command(command)
|
208
|
+
completed!
|
178
209
|
end
|
179
210
|
|
180
211
|
def wait_for_all(*futures)
|
@@ -226,7 +257,11 @@ module Temporal
|
|
226
257
|
|
227
258
|
private
|
228
259
|
|
229
|
-
attr_reader :state_manager, :dispatcher, :
|
260
|
+
attr_reader :state_manager, :dispatcher, :workflow_class
|
261
|
+
|
262
|
+
def completed!
|
263
|
+
@completed = true
|
264
|
+
end
|
230
265
|
|
231
266
|
def schedule_command(command)
|
232
267
|
state_manager.schedule(command)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'temporal/errors'
|
2
|
+
|
3
|
+
module Temporal
|
4
|
+
class Workflow
|
5
|
+
class Errors
|
6
|
+
extend Concerns::Payloads
|
7
|
+
|
8
|
+
# Convert a failure returned from the server to an Error to raise to the client
|
9
|
+
# failure: Temporal::Api::Failure::V1::Failure
|
10
|
+
def self.generate_error(failure, default_exception_class = StandardError)
|
11
|
+
case failure.failure_info
|
12
|
+
when :application_failure_info
|
13
|
+
exception_class = safe_constantize(failure.application_failure_info.type)
|
14
|
+
exception_class ||= default_exception_class
|
15
|
+
message = from_details_payloads(failure.application_failure_info.details)
|
16
|
+
backtrace = failure.stack_trace.split("\n")
|
17
|
+
|
18
|
+
exception_class.new(message).tap do |exception|
|
19
|
+
exception.set_backtrace(backtrace) if !backtrace.empty?
|
20
|
+
end
|
21
|
+
when :timeout_failure_info
|
22
|
+
TimeoutError.new("Timeout type: #{failure.timeout_failure_info.timeout_type.to_s}")
|
23
|
+
when :canceled_failure_info
|
24
|
+
# TODO: Distinguish between different entity cancellations
|
25
|
+
StandardError.new(from_payloads(failure.canceled_failure_info.details))
|
26
|
+
else
|
27
|
+
StandardError.new(failure.message)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private_class_method def self.safe_constantize(const)
|
32
|
+
Object.const_get(const) if Object.const_defined?(const)
|
33
|
+
rescue NameError
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -34,7 +34,7 @@ module Temporal
|
|
34
34
|
attr_reader :workflow_class, :dispatcher, :state_manager, :history
|
35
35
|
|
36
36
|
def execute_workflow(input, metadata)
|
37
|
-
context = Workflow::Context.new(state_manager, dispatcher, metadata)
|
37
|
+
context = Workflow::Context.new(state_manager, dispatcher, workflow_class, metadata)
|
38
38
|
|
39
39
|
Fiber.new do
|
40
40
|
workflow_class.execute_in_context(context, input)
|
@@ -3,13 +3,14 @@ require 'fiber'
|
|
3
3
|
module Temporal
|
4
4
|
class Workflow
|
5
5
|
class Future
|
6
|
-
attr_reader :target, :
|
6
|
+
attr_reader :target, :success_callbacks, :failure_callbacks
|
7
7
|
|
8
8
|
def initialize(target, context, cancelation_id: nil)
|
9
9
|
@target = target
|
10
10
|
@context = context
|
11
11
|
@cancelation_id = cancelation_id
|
12
|
-
@
|
12
|
+
@success_callbacks = []
|
13
|
+
@failure_callbacks = []
|
13
14
|
@ready = false
|
14
15
|
@failed = false
|
15
16
|
@result = nil
|
@@ -52,14 +53,25 @@ module Temporal
|
|
52
53
|
@failed = true
|
53
54
|
end
|
54
55
|
|
56
|
+
# When the activity completes successfully, the block will be called with any result
|
55
57
|
def done(&block)
|
56
|
-
# do nothing
|
57
|
-
return if failed?
|
58
|
-
|
59
58
|
if ready?
|
60
59
|
block.call(result)
|
61
60
|
else
|
62
|
-
|
61
|
+
# If the future is still outstanding, schedule a callback for invocation by the
|
62
|
+
# workflow context when the workflow or activity is finished
|
63
|
+
success_callbacks << block
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# When the activity fails, the block will be called with the exception
|
68
|
+
def failed(&block)
|
69
|
+
if failed?
|
70
|
+
block.call(exception)
|
71
|
+
else
|
72
|
+
# If the future is still outstanding, schedule a callback for invocation by the
|
73
|
+
# workflow context when the workflow or activity is finished
|
74
|
+
failure_callbacks << block
|
63
75
|
end
|
64
76
|
end
|
65
77
|
|
@@ -10,8 +10,6 @@ module Temporal
|
|
10
10
|
ACTIVITY_TASK_CANCELED
|
11
11
|
TIMER_FIRED
|
12
12
|
REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED
|
13
|
-
WORKFLOW_EXECUTION_SIGNALED
|
14
|
-
WORKFLOW_EXECUTION_TERMINATED
|
15
13
|
SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED
|
16
14
|
EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED
|
17
15
|
EXTERNAL_WORKFLOW_EXECUTION_SIGNALED
|
@@ -46,7 +44,7 @@ module Temporal
|
|
46
44
|
case type
|
47
45
|
when 'TIMER_FIRED'
|
48
46
|
attributes.started_event_id
|
49
|
-
when 'WORKFLOW_EXECUTION_SIGNALED'
|
47
|
+
when 'WORKFLOW_EXECUTION_SIGNALED', 'WORKFLOW_EXECUTION_TERMINATED'
|
50
48
|
1 # fixed id for everything related to current workflow
|
51
49
|
when *EVENT_TYPES
|
52
50
|
attributes.scheduled_event_id
|