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,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
|