temporal-ruby 0.0.0 → 0.0.1.pre.pre1
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/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,22 @@
|
|
|
1
|
+
module Temporal
|
|
2
|
+
module Saga
|
|
3
|
+
class Result
|
|
4
|
+
attr_reader :rollback_reason
|
|
5
|
+
|
|
6
|
+
def initialize(completed, rollback_reason = nil)
|
|
7
|
+
@completed = completed
|
|
8
|
+
@rollback_reason = rollback_reason
|
|
9
|
+
|
|
10
|
+
freeze
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def completed?
|
|
14
|
+
@completed
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def compensated?
|
|
18
|
+
!completed?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Temporal
|
|
2
|
+
module Saga
|
|
3
|
+
class Saga
|
|
4
|
+
def initialize(context)
|
|
5
|
+
@context = context
|
|
6
|
+
@compensations = []
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def add_compensation(activity, *args)
|
|
10
|
+
compensations << [activity, args]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def compensate
|
|
14
|
+
compensations.reverse_each do |(activity, args)|
|
|
15
|
+
context.execute_activity!(activity, *args)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
attr_reader :context, :compensations
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'temporal/testing/temporal_override'
|
|
2
|
+
require 'temporal/testing/workflow_override'
|
|
3
|
+
|
|
4
|
+
module Temporal
|
|
5
|
+
module Testing
|
|
6
|
+
DISABLED_MODE = nil
|
|
7
|
+
LOCAL_MODE = :local
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def local!(&block)
|
|
11
|
+
set_mode(LOCAL_MODE, &block)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def disabled!(&block)
|
|
15
|
+
set_mode(DISABLED_MODE, &block)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def disabled?
|
|
19
|
+
mode == DISABLED_MODE
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def local?
|
|
23
|
+
mode == LOCAL_MODE
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :mode
|
|
29
|
+
|
|
30
|
+
def set_mode(new_mode, &block)
|
|
31
|
+
if block_given?
|
|
32
|
+
with_mode(new_mode, &block)
|
|
33
|
+
else
|
|
34
|
+
@mode = new_mode
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def with_mode(new_mode, &block)
|
|
39
|
+
previous_mode = mode
|
|
40
|
+
@mode = new_mode
|
|
41
|
+
yield
|
|
42
|
+
ensure
|
|
43
|
+
@mode = previous_mode
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Temporal.singleton_class.prepend Temporal::Testing::TemporalOverride
|
|
50
|
+
Temporal::Workflow.extend Temporal::Testing::WorkflowOverride
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Temporal
|
|
2
|
+
module Testing
|
|
3
|
+
class FutureRegistry
|
|
4
|
+
def initialize
|
|
5
|
+
@store = {}
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def register(token, future)
|
|
9
|
+
raise 'already registered' if store.key?(token)
|
|
10
|
+
|
|
11
|
+
store[token] = future
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def complete(token, result)
|
|
15
|
+
store[token].set(result)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def fail(token, error)
|
|
19
|
+
store[token].fail(error.class.name, error.message)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
attr_reader :store
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
require 'temporal/uuid'
|
|
3
|
+
require 'temporal/activity/context'
|
|
4
|
+
|
|
5
|
+
module Temporal
|
|
6
|
+
module Testing
|
|
7
|
+
class LocalActivityContext < Activity::Context
|
|
8
|
+
def initialize(metadata)
|
|
9
|
+
super(nil, metadata)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def heartbeat(details = nil)
|
|
13
|
+
raise NotImplementedError, 'not yet available for testing'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
require 'temporal/testing/local_activity_context'
|
|
3
|
+
require 'temporal/testing/workflow_execution'
|
|
4
|
+
require 'temporal/execution_options'
|
|
5
|
+
require 'temporal/metadata/activity'
|
|
6
|
+
require 'temporal/workflow/future'
|
|
7
|
+
require 'temporal/workflow/history/event_target'
|
|
8
|
+
|
|
9
|
+
module Temporal
|
|
10
|
+
module Testing
|
|
11
|
+
class LocalWorkflowContext
|
|
12
|
+
attr_reader :headers
|
|
13
|
+
|
|
14
|
+
def initialize(execution, workflow_id, run_id, disabled_releases, headers = {})
|
|
15
|
+
@last_event_id = 0
|
|
16
|
+
@execution = execution
|
|
17
|
+
@run_id = run_id
|
|
18
|
+
@workflow_id = workflow_id
|
|
19
|
+
@disabled_releases = disabled_releases
|
|
20
|
+
@headers = headers
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def logger
|
|
24
|
+
Temporal.logger
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def has_release?(change_name)
|
|
28
|
+
!disabled_releases.include?(change_name.to_s)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def execute_activity(activity_class, *input, **args)
|
|
32
|
+
options = args.delete(:options) || {}
|
|
33
|
+
input << args unless args.empty?
|
|
34
|
+
|
|
35
|
+
event_id = next_event_id
|
|
36
|
+
activity_id = options[:activity_id] || event_id
|
|
37
|
+
|
|
38
|
+
target = Workflow::History::EventTarget.new(event_id, Workflow::History::EventTarget::ACTIVITY_TYPE)
|
|
39
|
+
future = Workflow::Future.new(target, self, cancelation_id: activity_id)
|
|
40
|
+
|
|
41
|
+
execution_options = ExecutionOptions.new(activity_class, options)
|
|
42
|
+
metadata = Metadata::Activity.new(
|
|
43
|
+
namespace: execution_options.namespace,
|
|
44
|
+
id: activity_id,
|
|
45
|
+
name: execution_options.name,
|
|
46
|
+
task_token: nil,
|
|
47
|
+
attempt: 1,
|
|
48
|
+
workflow_run_id: run_id,
|
|
49
|
+
workflow_id: workflow_id,
|
|
50
|
+
workflow_name: nil, # not yet used, but will be in the future
|
|
51
|
+
headers: execution_options.headers
|
|
52
|
+
)
|
|
53
|
+
context = LocalActivityContext.new(metadata)
|
|
54
|
+
|
|
55
|
+
result = activity_class.execute_in_context(context, input)
|
|
56
|
+
|
|
57
|
+
if context.async?
|
|
58
|
+
execution.register_future(context.async_token, future)
|
|
59
|
+
else
|
|
60
|
+
# Fulfil the future straigt away for non-async activities
|
|
61
|
+
future.set(result)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
future
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def execute_activity!(activity_class, *input, **args)
|
|
68
|
+
future = execute_activity(activity_class, *input, **args)
|
|
69
|
+
result = future.get
|
|
70
|
+
|
|
71
|
+
raise future.exception if future.failed?
|
|
72
|
+
|
|
73
|
+
result
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def execute_local_activity(activity_class, *input, **args)
|
|
77
|
+
options = args.delete(:options) || {}
|
|
78
|
+
input << args unless args.empty?
|
|
79
|
+
|
|
80
|
+
execution_options = ExecutionOptions.new(activity_class, options)
|
|
81
|
+
activity_id = options[:activity_id] || SecureRandom.uuid
|
|
82
|
+
metadata = Metadata::Activity.new(
|
|
83
|
+
namespace: execution_options.namespace,
|
|
84
|
+
id: activity_id,
|
|
85
|
+
name: execution_options.name,
|
|
86
|
+
task_token: nil,
|
|
87
|
+
attempt: 1,
|
|
88
|
+
workflow_run_id: run_id,
|
|
89
|
+
workflow_id: workflow_id,
|
|
90
|
+
workflow_name: nil, # not yet used, but will be in the future
|
|
91
|
+
headers: execution_options.headers
|
|
92
|
+
)
|
|
93
|
+
context = LocalActivityContext.new(metadata)
|
|
94
|
+
|
|
95
|
+
activity_class.execute_in_context(context, input)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def execute_workflow(workflow_class, *input, **args)
|
|
99
|
+
raise NotImplementedError, 'not yet available for testing'
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def execute_workflow!(workflow_class, *input, **args)
|
|
103
|
+
options = args.delete(:options) || {}
|
|
104
|
+
input << args unless args.empty?
|
|
105
|
+
|
|
106
|
+
execution = WorkflowExecution.new
|
|
107
|
+
workflow_id = SecureRandom.uuid
|
|
108
|
+
run_id = SecureRandom.uuid
|
|
109
|
+
execution_options = ExecutionOptions.new(workflow_class, options)
|
|
110
|
+
context = Temporal::Testing::LocalWorkflowContext.new(
|
|
111
|
+
execution, workflow_id, run_id, workflow_class.disabled_releases, execution_options.headers
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
workflow_class.execute_in_context(context, input)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def side_effect(&block)
|
|
118
|
+
block.call
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def sleep(timeout)
|
|
122
|
+
::Kernel.sleep timeout
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def start_timer(timeout, timer_id = nil)
|
|
126
|
+
raise NotImplementedError, 'not yet available for testing'
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def cancel_timer(timer_id)
|
|
130
|
+
raise NotImplementedError, 'not yet available for testing'
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def complete(result = nil)
|
|
134
|
+
result
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def fail(exception)
|
|
138
|
+
raise exception
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def wait_for_all(*futures)
|
|
142
|
+
futures.each(&:wait)
|
|
143
|
+
|
|
144
|
+
return
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def wait_for(future)
|
|
148
|
+
# Point of communication
|
|
149
|
+
Fiber.yield while !future.finished?
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def now
|
|
153
|
+
Time.now
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def on_signal(&block)
|
|
157
|
+
raise NotImplementedError, 'not yet available for testing'
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def cancel_activity(activity_id)
|
|
161
|
+
raise NotImplementedError, 'not yet available for testing'
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def cancel(target, cancelation_id)
|
|
165
|
+
raise NotImplementedError, 'not yet available for testing'
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
attr_reader :execution, :run_id, :workflow_id, :disabled_releases
|
|
171
|
+
|
|
172
|
+
def next_event_id
|
|
173
|
+
@last_event_id += 1
|
|
174
|
+
@last_event_id
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
require 'temporal/activity/async_token'
|
|
3
|
+
require 'temporal/workflow/execution_info'
|
|
4
|
+
require 'temporal/testing/workflow_execution'
|
|
5
|
+
require 'temporal/testing/local_workflow_context'
|
|
6
|
+
|
|
7
|
+
module Temporal
|
|
8
|
+
module Testing
|
|
9
|
+
module TemporalOverride
|
|
10
|
+
def start_workflow(workflow, *input, **args)
|
|
11
|
+
return super if Temporal::Testing.disabled?
|
|
12
|
+
|
|
13
|
+
if Temporal::Testing.local?
|
|
14
|
+
start_locally(workflow, *input, **args)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def fetch_workflow_execution_info(_namespace, workflow_id, run_id)
|
|
19
|
+
return super if Temporal::Testing.disabled?
|
|
20
|
+
|
|
21
|
+
execution = executions[[workflow_id, run_id]]
|
|
22
|
+
|
|
23
|
+
Workflow::ExecutionInfo.new(
|
|
24
|
+
workflow: nil,
|
|
25
|
+
workflow_id: workflow_id,
|
|
26
|
+
run_id: run_id,
|
|
27
|
+
start_time: nil,
|
|
28
|
+
close_time: nil,
|
|
29
|
+
status: execution.status,
|
|
30
|
+
history_length: nil,
|
|
31
|
+
).freeze
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def complete_activity(async_token, result = nil)
|
|
35
|
+
return super if Temporal::Testing.disabled?
|
|
36
|
+
|
|
37
|
+
details = Activity::AsyncToken.decode(async_token)
|
|
38
|
+
execution = executions[[details.workflow_id, details.run_id]]
|
|
39
|
+
|
|
40
|
+
execution.complete_activity(async_token, result)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def fail_activity(async_token, exception)
|
|
44
|
+
return super if Temporal::Testing.disabled?
|
|
45
|
+
|
|
46
|
+
details = Activity::AsyncToken.decode(async_token)
|
|
47
|
+
execution = executions[[details.workflow_id, details.run_id]]
|
|
48
|
+
|
|
49
|
+
execution.fail_activity(async_token, exception)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def executions
|
|
55
|
+
@executions ||= {}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def start_locally(workflow, *input, **args)
|
|
59
|
+
options = args.delete(:options) || {}
|
|
60
|
+
input << args unless args.empty?
|
|
61
|
+
|
|
62
|
+
reuse_policy = options[:workflow_id_reuse_policy] || :allow_failed
|
|
63
|
+
workflow_id = options[:workflow_id] || SecureRandom.uuid
|
|
64
|
+
run_id = SecureRandom.uuid
|
|
65
|
+
|
|
66
|
+
if !allowed?(workflow_id, reuse_policy)
|
|
67
|
+
raise Temporal::WorkflowExecutionAlreadyStartedFailure.new(
|
|
68
|
+
"Workflow execution already started for id #{workflow_id}, reuse policy #{reuse_policy}",
|
|
69
|
+
previous_run_id(workflow_id)
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
execution = WorkflowExecution.new
|
|
74
|
+
executions[[workflow_id, run_id]] = execution
|
|
75
|
+
|
|
76
|
+
execution_options = ExecutionOptions.new(workflow, options)
|
|
77
|
+
headers = execution_options.headers
|
|
78
|
+
context = Temporal::Testing::LocalWorkflowContext.new(
|
|
79
|
+
execution, workflow_id, run_id, workflow.disabled_releases, headers
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
execution.run do
|
|
83
|
+
workflow.execute_in_context(context, input)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
run_id
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def allowed?(workflow_id, reuse_policy)
|
|
90
|
+
disallowed_statuses = disallowed_statuses_for(reuse_policy)
|
|
91
|
+
|
|
92
|
+
# there isn't a single execution in a dissallowed status
|
|
93
|
+
executions.none? do |(w_id, _), execution|
|
|
94
|
+
w_id == workflow_id && disallowed_statuses.include?(execution.status)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def previous_run_id(workflow_id)
|
|
99
|
+
executions.each do |(w_id, run_id), _|
|
|
100
|
+
return run_id if w_id == workflow_id
|
|
101
|
+
end
|
|
102
|
+
nil
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def disallowed_statuses_for(reuse_policy)
|
|
106
|
+
case reuse_policy
|
|
107
|
+
when :allow_failed
|
|
108
|
+
[Workflow::ExecutionInfo::RUNNING_STATUS, Workflow::ExecutionInfo::COMPLETED_STATUS]
|
|
109
|
+
when :allow
|
|
110
|
+
[Workflow::ExecutionInfo::RUNNING_STATUS]
|
|
111
|
+
when :reject
|
|
112
|
+
[
|
|
113
|
+
Workflow::ExecutionInfo::RUNNING_STATUS,
|
|
114
|
+
Workflow::ExecutionInfo::FAILED_STATUS,
|
|
115
|
+
Workflow::ExecutionInfo::COMPLETED_STATUS
|
|
116
|
+
]
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'temporal/testing/future_registry'
|
|
2
|
+
|
|
3
|
+
module Temporal
|
|
4
|
+
module Testing
|
|
5
|
+
class WorkflowExecution
|
|
6
|
+
attr_reader :status
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@status = Workflow::ExecutionInfo::RUNNING_STATUS
|
|
10
|
+
@futures = FutureRegistry.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run(&block)
|
|
14
|
+
@fiber = Fiber.new(&block)
|
|
15
|
+
resume
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def resume
|
|
19
|
+
fiber.resume
|
|
20
|
+
@status = Workflow::ExecutionInfo::COMPLETED_STATUS unless fiber.alive?
|
|
21
|
+
rescue StandardError
|
|
22
|
+
@status = Workflow::ExecutionInfo::FAILED_STATUS
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def register_future(token, future)
|
|
26
|
+
futures.register(token, future)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def complete_activity(token, result)
|
|
30
|
+
futures.complete(token, result)
|
|
31
|
+
resume
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def fail_activity(token, exception)
|
|
35
|
+
futures.fail(token, exception)
|
|
36
|
+
resume
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
attr_reader :fiber, :futures
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|