cadence-ruby 0.0.0 → 0.1.0
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 +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,30 @@
|
|
1
|
+
module Cadence
|
2
|
+
module Middleware
|
3
|
+
class Chain
|
4
|
+
def initialize(entries = [])
|
5
|
+
@middleware = entries.map(&:init_middleware)
|
6
|
+
end
|
7
|
+
|
8
|
+
def invoke(metadata)
|
9
|
+
result = nil
|
10
|
+
chain = middleware.dup
|
11
|
+
|
12
|
+
traverse_chain = lambda do
|
13
|
+
if chain.empty?
|
14
|
+
result = yield
|
15
|
+
else
|
16
|
+
chain.shift.call(metadata, &traverse_chain)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
traverse_chain.call
|
21
|
+
|
22
|
+
result
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :middleware
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'cadence/errors'
|
2
|
+
|
3
|
+
module Cadence
|
4
|
+
class RetryPolicy < Struct.new(:interval, :backoff, :max_interval, :max_attempts,
|
5
|
+
:expiration_interval, :non_retriable_errors, keyword_init: true)
|
6
|
+
|
7
|
+
class InvalidRetryPolicy < ClientError; end
|
8
|
+
|
9
|
+
def validate!
|
10
|
+
unless interval && backoff
|
11
|
+
raise InvalidRetryPolicy, 'interval and backoff must be set'
|
12
|
+
end
|
13
|
+
|
14
|
+
unless max_attempts || expiration_interval
|
15
|
+
raise InvalidRetryPolicy, 'max_attempts or expiration_interval must be set'
|
16
|
+
end
|
17
|
+
|
18
|
+
unless [interval, max_interval, expiration_interval].compact.all? { |arg| arg.is_a?(Integer) }
|
19
|
+
raise InvalidRetryPolicy, 'All intervals must be specified in whole seconds'
|
20
|
+
end
|
21
|
+
|
22
|
+
unless [interval, max_interval, expiration_interval].compact.all? { |arg| arg > 0 }
|
23
|
+
raise InvalidRetryPolicy, 'All intervals must be greater than 0'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'cadence/saga/saga'
|
2
|
+
require 'cadence/saga/result'
|
3
|
+
|
4
|
+
module Cadence
|
5
|
+
module Saga
|
6
|
+
module Concern
|
7
|
+
def run_saga(configuration = {}, &block)
|
8
|
+
saga = Cadence::Saga::Saga.new(workflow)
|
9
|
+
|
10
|
+
block.call(saga)
|
11
|
+
|
12
|
+
Result.new(true)
|
13
|
+
rescue StandardError => error # TODO: is there a need for a specialized error here?
|
14
|
+
logger.error("Saga execution aborted: #{error.inspect}")
|
15
|
+
logger.debug(error.backtrace.join("\n"))
|
16
|
+
|
17
|
+
if compensate?(error, **configuration)
|
18
|
+
logger.error('Saga compensating')
|
19
|
+
saga.compensate
|
20
|
+
Result.new(false, error)
|
21
|
+
else
|
22
|
+
logger.error('Saga not compensating')
|
23
|
+
raise error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def compensate?(error, compensate_on: [], do_not_compensate_on: [])
|
28
|
+
error_class = error.class
|
29
|
+
if compensate_on.any?
|
30
|
+
compensate_on.include?(error_class)
|
31
|
+
else
|
32
|
+
!do_not_compensate_on.include?(error_class)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Cadence
|
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 Cadence
|
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 'cadence/testing/cadence_override'
|
2
|
+
require 'cadence/testing/workflow_override'
|
3
|
+
|
4
|
+
module Cadence
|
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
|
+
Cadence.singleton_class.prepend Cadence::Testing::CadenceOverride
|
50
|
+
Cadence::Workflow.extend Cadence::Testing::WorkflowOverride
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'cadence/activity/async_token'
|
3
|
+
require 'cadence/workflow/execution_info'
|
4
|
+
require 'cadence/testing/workflow_execution'
|
5
|
+
require 'cadence/testing/local_workflow_context'
|
6
|
+
|
7
|
+
module Cadence
|
8
|
+
module Testing
|
9
|
+
module CadenceOverride
|
10
|
+
def start_workflow(workflow, *input, **args)
|
11
|
+
return super if Cadence::Testing.disabled?
|
12
|
+
|
13
|
+
if Cadence::Testing.local?
|
14
|
+
start_locally(workflow, *input, **args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def fetch_workflow_execution_info(_domain, workflow_id, run_id)
|
19
|
+
return super if Cadence::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 Cadence::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, error)
|
44
|
+
return super if Cadence::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, error)
|
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 CadenceThrift::WorkflowExecutionAlreadyStartedError,
|
68
|
+
"Workflow execution already started for id #{workflow_id}, reuse policy #{reuse_policy}"
|
69
|
+
end
|
70
|
+
|
71
|
+
execution = WorkflowExecution.new
|
72
|
+
executions[[workflow_id, run_id]] = execution
|
73
|
+
|
74
|
+
execution_options = ExecutionOptions.new(workflow, options)
|
75
|
+
headers = execution_options.headers
|
76
|
+
context = Cadence::Testing::LocalWorkflowContext.new(
|
77
|
+
execution, workflow_id, run_id, workflow.disabled_releases, headers
|
78
|
+
)
|
79
|
+
|
80
|
+
execution.run do
|
81
|
+
workflow.execute_in_context(context, input)
|
82
|
+
end
|
83
|
+
|
84
|
+
run_id
|
85
|
+
end
|
86
|
+
|
87
|
+
def allowed?(workflow_id, reuse_policy)
|
88
|
+
disallowed_statuses = disallowed_statuses_for(reuse_policy)
|
89
|
+
|
90
|
+
# there isn't a single execution in a dissallowed status
|
91
|
+
executions.none? do |(w_id, _), execution|
|
92
|
+
w_id == workflow_id && disallowed_statuses.include?(execution.status)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def disallowed_statuses_for(reuse_policy)
|
97
|
+
case reuse_policy
|
98
|
+
when :allow_failed
|
99
|
+
[Workflow::ExecutionInfo::RUNNING_STATUS, Workflow::ExecutionInfo::COMPLETED_STATUS]
|
100
|
+
when :allow
|
101
|
+
[Workflow::ExecutionInfo::RUNNING_STATUS]
|
102
|
+
when :reject
|
103
|
+
[
|
104
|
+
Workflow::ExecutionInfo::RUNNING_STATUS,
|
105
|
+
Workflow::ExecutionInfo::FAILED_STATUS,
|
106
|
+
Workflow::ExecutionInfo::COMPLETED_STATUS
|
107
|
+
]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Cadence
|
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 'cadence/uuid'
|
3
|
+
require 'cadence/activity/context'
|
4
|
+
|
5
|
+
module Cadence
|
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,207 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'cadence/testing/local_activity_context'
|
3
|
+
require 'cadence/testing/workflow_execution'
|
4
|
+
require 'cadence/execution_options'
|
5
|
+
require 'cadence/metadata/activity'
|
6
|
+
require 'cadence/workflow/future'
|
7
|
+
require 'cadence/workflow/history/event_target'
|
8
|
+
|
9
|
+
module Cadence
|
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
|
+
Cadence.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
|
+
domain: execution_options.domain,
|
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
|
+
timeouts: {
|
53
|
+
start_to_close: 30,
|
54
|
+
schedule_to_close: 60,
|
55
|
+
heartbeat: 5
|
56
|
+
}
|
57
|
+
)
|
58
|
+
context = LocalActivityContext.new(metadata)
|
59
|
+
|
60
|
+
result = activity_class.execute_in_context(context, input)
|
61
|
+
|
62
|
+
if context.async?
|
63
|
+
execution.register_future(context.async_token, future)
|
64
|
+
else
|
65
|
+
# Fulfil the future straigt away for non-async activities
|
66
|
+
future.set(result)
|
67
|
+
end
|
68
|
+
|
69
|
+
future
|
70
|
+
end
|
71
|
+
|
72
|
+
def execute_activity!(activity_class, *input, **args)
|
73
|
+
future = execute_activity(activity_class, *input, **args)
|
74
|
+
result = future.get
|
75
|
+
|
76
|
+
if future.failed?
|
77
|
+
reason, details = result
|
78
|
+
|
79
|
+
error_class = safe_constantize(reason) || Cadence::ActivityException
|
80
|
+
|
81
|
+
raise error_class, details
|
82
|
+
end
|
83
|
+
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
87
|
+
def execute_local_activity(activity_class, *input, **args)
|
88
|
+
options = args.delete(:options) || {}
|
89
|
+
input << args unless args.empty?
|
90
|
+
|
91
|
+
execution_options = ExecutionOptions.new(activity_class, options)
|
92
|
+
activity_id = options[:activity_id] || SecureRandom.uuid
|
93
|
+
metadata = Metadata::Activity.new(
|
94
|
+
domain: execution_options.domain,
|
95
|
+
id: activity_id,
|
96
|
+
name: execution_options.name,
|
97
|
+
task_token: nil,
|
98
|
+
attempt: 1,
|
99
|
+
workflow_run_id: run_id,
|
100
|
+
workflow_id: workflow_id,
|
101
|
+
workflow_name: nil, # not yet used, but will be in the future
|
102
|
+
headers: execution_options.headers,
|
103
|
+
timeouts: {
|
104
|
+
schedule_to_close: 60,
|
105
|
+
start_to_close: 30,
|
106
|
+
heartbeat: 5
|
107
|
+
}
|
108
|
+
)
|
109
|
+
context = LocalActivityContext.new(metadata)
|
110
|
+
|
111
|
+
activity_class.execute_in_context(context, input)
|
112
|
+
end
|
113
|
+
|
114
|
+
def execute_workflow(workflow_class, *input, **args)
|
115
|
+
raise NotImplementedError, 'not yet available for testing'
|
116
|
+
end
|
117
|
+
|
118
|
+
def execute_workflow!(workflow_class, *input, **args)
|
119
|
+
options = args.delete(:options) || {}
|
120
|
+
input << args unless args.empty?
|
121
|
+
|
122
|
+
execution = WorkflowExecution.new
|
123
|
+
workflow_id = SecureRandom.uuid
|
124
|
+
run_id = SecureRandom.uuid
|
125
|
+
execution_options = ExecutionOptions.new(workflow_class, options)
|
126
|
+
context = Cadence::Testing::LocalWorkflowContext.new(
|
127
|
+
execution, workflow_id, run_id, workflow_class.disabled_releases, execution_options.headers
|
128
|
+
)
|
129
|
+
|
130
|
+
workflow_class.execute_in_context(context, input)
|
131
|
+
end
|
132
|
+
|
133
|
+
def side_effect(&block)
|
134
|
+
block.call
|
135
|
+
end
|
136
|
+
|
137
|
+
def sleep(timeout)
|
138
|
+
::Kernel.sleep timeout
|
139
|
+
end
|
140
|
+
|
141
|
+
def sleep_until(end_time)
|
142
|
+
delay = (end_time.to_time - now).to_i
|
143
|
+
sleep(delay) if delay > 0
|
144
|
+
end
|
145
|
+
|
146
|
+
def start_timer(timeout, timer_id = nil)
|
147
|
+
raise NotImplementedError, 'not yet available for testing'
|
148
|
+
end
|
149
|
+
|
150
|
+
def cancel_timer(timer_id)
|
151
|
+
raise NotImplementedError, 'not yet available for testing'
|
152
|
+
end
|
153
|
+
|
154
|
+
def complete(result = nil)
|
155
|
+
result
|
156
|
+
end
|
157
|
+
|
158
|
+
def fail(reason, details = nil)
|
159
|
+
error_class = safe_constantize(reason) || StandardError
|
160
|
+
|
161
|
+
raise error_class, details
|
162
|
+
end
|
163
|
+
|
164
|
+
def wait_for_all(*futures)
|
165
|
+
futures.each(&:wait)
|
166
|
+
|
167
|
+
return
|
168
|
+
end
|
169
|
+
|
170
|
+
def wait_for(future)
|
171
|
+
# Point of communication
|
172
|
+
Fiber.yield while !future.finished?
|
173
|
+
end
|
174
|
+
|
175
|
+
def now
|
176
|
+
Time.now
|
177
|
+
end
|
178
|
+
|
179
|
+
def on_signal(&block)
|
180
|
+
raise NotImplementedError, 'not yet available for testing'
|
181
|
+
end
|
182
|
+
|
183
|
+
def cancel_activity(activity_id)
|
184
|
+
raise NotImplementedError, 'not yet available for testing'
|
185
|
+
end
|
186
|
+
|
187
|
+
def cancel(target, cancelation_id)
|
188
|
+
raise NotImplementedError, 'not yet available for testing'
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
attr_reader :execution, :run_id, :workflow_id, :disabled_releases
|
194
|
+
|
195
|
+
def next_event_id
|
196
|
+
@last_event_id += 1
|
197
|
+
@last_event_id
|
198
|
+
end
|
199
|
+
|
200
|
+
def safe_constantize(const)
|
201
|
+
Object.const_get(const) if Object.const_defined?(const)
|
202
|
+
rescue NameError
|
203
|
+
nil
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|