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
data/cadence.gemspec
CHANGED
@@ -7,10 +7,17 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.email = ['anthony.dmitriyev@coinbase.com']
|
8
8
|
|
9
9
|
spec.summary = 'Cadence Ruby client'
|
10
|
-
spec.description = 'A
|
10
|
+
spec.description = 'A Ruby client for implementing Cadence workflows and activities in Ruby'
|
11
11
|
spec.homepage = 'https://github.com/coinbase/cadence-ruby'
|
12
12
|
spec.license = 'Apache-2.0'
|
13
13
|
|
14
14
|
spec.require_paths = ['lib']
|
15
|
-
spec.files = [
|
15
|
+
spec.files = Dir["{lib,rbi}/**/*.*"] + %w(cadence.gemspec Gemfile LICENSE README.md)
|
16
|
+
|
17
|
+
spec.add_dependency 'thrift'
|
18
|
+
spec.add_dependency 'oj'
|
19
|
+
|
20
|
+
spec.add_development_dependency 'pry'
|
21
|
+
spec.add_development_dependency 'rspec'
|
22
|
+
spec.add_development_dependency 'fabrication'
|
16
23
|
end
|
data/lib/cadence-ruby.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'cadence'
|
data/lib/cadence.rb
CHANGED
@@ -1,2 +1,178 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'cadence/configuration'
|
3
|
+
require 'cadence/execution_options'
|
4
|
+
require 'cadence/client'
|
5
|
+
require 'cadence/activity'
|
6
|
+
require 'cadence/activity/async_token'
|
7
|
+
require 'cadence/workflow'
|
8
|
+
require 'cadence/workflow/history'
|
9
|
+
require 'cadence/workflow/execution_info'
|
10
|
+
require 'cadence/metrics'
|
11
|
+
|
1
12
|
module Cadence
|
13
|
+
class << self
|
14
|
+
def start_workflow(workflow, *input, **args)
|
15
|
+
options = args.delete(:options) || {}
|
16
|
+
input << args unless args.empty?
|
17
|
+
|
18
|
+
execution_options = ExecutionOptions.new(workflow, options)
|
19
|
+
workflow_id = options[:workflow_id] || SecureRandom.uuid
|
20
|
+
|
21
|
+
response = client.start_workflow_execution(
|
22
|
+
domain: execution_options.domain,
|
23
|
+
workflow_id: workflow_id,
|
24
|
+
workflow_name: execution_options.name,
|
25
|
+
task_list: execution_options.task_list,
|
26
|
+
input: input,
|
27
|
+
execution_timeout: execution_options.timeouts[:execution],
|
28
|
+
task_timeout: execution_options.timeouts[:task],
|
29
|
+
workflow_id_reuse_policy: options[:workflow_id_reuse_policy],
|
30
|
+
headers: execution_options.headers
|
31
|
+
)
|
32
|
+
|
33
|
+
response.runId
|
34
|
+
end
|
35
|
+
|
36
|
+
def schedule_workflow(workflow, cron_schedule, *input, **args)
|
37
|
+
options = args.delete(:options) || {}
|
38
|
+
input << args unless args.empty?
|
39
|
+
|
40
|
+
execution_options = ExecutionOptions.new(workflow, options)
|
41
|
+
workflow_id = options[:workflow_id] || SecureRandom.uuid
|
42
|
+
|
43
|
+
response = client.start_workflow_execution(
|
44
|
+
domain: execution_options.domain,
|
45
|
+
workflow_id: workflow_id,
|
46
|
+
workflow_name: execution_options.name,
|
47
|
+
task_list: execution_options.task_list,
|
48
|
+
input: input,
|
49
|
+
execution_timeout: execution_options.timeouts[:execution],
|
50
|
+
task_timeout: execution_options.timeouts[:task],
|
51
|
+
workflow_id_reuse_policy: options[:workflow_id_reuse_policy],
|
52
|
+
headers: execution_options.headers,
|
53
|
+
cron_schedule: cron_schedule
|
54
|
+
)
|
55
|
+
|
56
|
+
response.runId
|
57
|
+
end
|
58
|
+
|
59
|
+
def register_domain(name, description = nil)
|
60
|
+
client.register_domain(name: name, description: description)
|
61
|
+
rescue CadenceThrift::DomainAlreadyExistsError
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def signal_workflow(workflow, signal, workflow_id, run_id, input = nil)
|
66
|
+
client.signal_workflow_execution(
|
67
|
+
domain: workflow.domain, # TODO: allow passing domain instead
|
68
|
+
workflow_id: workflow_id,
|
69
|
+
run_id: run_id,
|
70
|
+
signal: signal,
|
71
|
+
input: input
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def reset_workflow(domain, workflow_id, run_id, decision_task_id: nil, reason: 'manual reset')
|
76
|
+
decision_task_id ||= get_last_completed_decision_task(domain, workflow_id, run_id)
|
77
|
+
raise Error, 'Could not find a completed decision task event' unless decision_task_id
|
78
|
+
|
79
|
+
response = client.reset_workflow_execution(
|
80
|
+
domain: domain,
|
81
|
+
workflow_id: workflow_id,
|
82
|
+
run_id: run_id,
|
83
|
+
reason: reason,
|
84
|
+
decision_task_event_id: decision_task_id
|
85
|
+
)
|
86
|
+
|
87
|
+
response.runId
|
88
|
+
end
|
89
|
+
|
90
|
+
def terminate_workflow(domain, workflow_id, run_id, reason: 'manual termination', details: nil)
|
91
|
+
client.terminate_workflow_execution(
|
92
|
+
domain: domain,
|
93
|
+
workflow_id: workflow_id,
|
94
|
+
run_id: run_id,
|
95
|
+
reason: reason,
|
96
|
+
details: details
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
def fetch_workflow_execution_info(domain, workflow_id, run_id)
|
101
|
+
response = client.describe_workflow_execution(
|
102
|
+
domain: domain,
|
103
|
+
workflow_id: workflow_id,
|
104
|
+
run_id: run_id
|
105
|
+
)
|
106
|
+
|
107
|
+
Workflow::ExecutionInfo.generate_from(response.workflowExecutionInfo)
|
108
|
+
end
|
109
|
+
|
110
|
+
def complete_activity(async_token, result = nil)
|
111
|
+
details = Activity::AsyncToken.decode(async_token)
|
112
|
+
|
113
|
+
client.respond_activity_task_completed_by_id(
|
114
|
+
domain: details.domain,
|
115
|
+
activity_id: details.activity_id,
|
116
|
+
workflow_id: details.workflow_id,
|
117
|
+
run_id: details.run_id,
|
118
|
+
result: result
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
def fail_activity(async_token, error)
|
123
|
+
details = Activity::AsyncToken.decode(async_token)
|
124
|
+
|
125
|
+
client.respond_activity_task_failed_by_id(
|
126
|
+
domain: details.domain,
|
127
|
+
activity_id: details.activity_id,
|
128
|
+
workflow_id: details.workflow_id,
|
129
|
+
run_id: details.run_id,
|
130
|
+
reason: error.class.name,
|
131
|
+
details: error.message
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
def configure(&block)
|
136
|
+
yield configuration
|
137
|
+
end
|
138
|
+
|
139
|
+
def configuration
|
140
|
+
@configuration ||= Configuration.new
|
141
|
+
end
|
142
|
+
|
143
|
+
def logger
|
144
|
+
configuration.logger
|
145
|
+
end
|
146
|
+
|
147
|
+
def metrics
|
148
|
+
@metrics ||= Metrics.new(configuration.metrics_adapter)
|
149
|
+
end
|
150
|
+
|
151
|
+
def get_workflow_history(domain:, workflow_id:, run_id:)
|
152
|
+
history_response = client.get_workflow_execution_history(
|
153
|
+
domain: domain,
|
154
|
+
workflow_id: workflow_id,
|
155
|
+
run_id: run_id
|
156
|
+
)
|
157
|
+
Workflow::History.new(history_response.history.events)
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def client
|
163
|
+
@client ||= Cadence::Client.generate
|
164
|
+
end
|
165
|
+
|
166
|
+
def get_last_completed_decision_task(domain, workflow_id, run_id)
|
167
|
+
history = get_workflow_history(
|
168
|
+
domain: domain,
|
169
|
+
workflow_id: workflow_id,
|
170
|
+
run_id: run_id
|
171
|
+
)
|
172
|
+
|
173
|
+
decision_task_event = history.last_completed_decision_task
|
174
|
+
|
175
|
+
decision_task_event&.id
|
176
|
+
end
|
177
|
+
end
|
2
178
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'cadence/activity/workflow_convenience_methods'
|
2
|
+
require 'cadence/concerns/executable'
|
3
|
+
require 'cadence/errors'
|
4
|
+
|
5
|
+
module Cadence
|
6
|
+
class Activity
|
7
|
+
extend WorkflowConvenienceMethods
|
8
|
+
extend Concerns::Executable
|
9
|
+
|
10
|
+
def self.execute_in_context(context, input)
|
11
|
+
activity = new(context)
|
12
|
+
activity.execute(*input)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(context)
|
16
|
+
@context = context
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute(*_args)
|
20
|
+
raise NotImplementedError, '#execute method must be implemented by a subclass'
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def activity
|
26
|
+
@context
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger
|
30
|
+
activity.logger
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Cadence
|
4
|
+
class Activity
|
5
|
+
class AsyncToken
|
6
|
+
SEPARATOR = '|'.freeze
|
7
|
+
|
8
|
+
attr_reader :domain, :activity_id, :workflow_id, :run_id
|
9
|
+
|
10
|
+
def self.encode(domain, activity_id, workflow_id, run_id)
|
11
|
+
new(domain, activity_id, workflow_id, run_id).to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.decode(token)
|
15
|
+
string = Base64.urlsafe_decode64(token)
|
16
|
+
domain, activity_id, workflow_id, run_id = string.split(SEPARATOR)
|
17
|
+
|
18
|
+
new(domain, activity_id, workflow_id, run_id)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(domain, activity_id, workflow_id, run_id)
|
22
|
+
@domain = domain
|
23
|
+
@activity_id = activity_id
|
24
|
+
@workflow_id = workflow_id
|
25
|
+
@run_id = run_id
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
parts = [domain, activity_id, workflow_id, run_id]
|
30
|
+
Base64.urlsafe_encode64(parts.join(SEPARATOR)).freeze
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# This context class is available in the activity implementation
|
2
|
+
# and provides context and methods for interacting with Cadence
|
3
|
+
#
|
4
|
+
require 'cadence/uuid'
|
5
|
+
require 'cadence/activity/async_token'
|
6
|
+
|
7
|
+
module Cadence
|
8
|
+
class Activity
|
9
|
+
class Context
|
10
|
+
def initialize(client, metadata)
|
11
|
+
@client = client
|
12
|
+
@metadata = metadata
|
13
|
+
@async = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def async
|
17
|
+
@async = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def async?
|
21
|
+
@async
|
22
|
+
end
|
23
|
+
|
24
|
+
def async_token
|
25
|
+
AsyncToken.encode(
|
26
|
+
metadata.domain,
|
27
|
+
metadata.id,
|
28
|
+
metadata.workflow_id,
|
29
|
+
metadata.workflow_run_id
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def heartbeat(details = nil)
|
34
|
+
logger.debug('Activity heartbeat')
|
35
|
+
client.record_activity_task_heartbeat(task_token: task_token, details: details)
|
36
|
+
end
|
37
|
+
|
38
|
+
def logger
|
39
|
+
Cadence.logger
|
40
|
+
end
|
41
|
+
|
42
|
+
def run_idem
|
43
|
+
UUID.v5(metadata.workflow_run_id.to_s, metadata.id.to_s)
|
44
|
+
end
|
45
|
+
alias idem run_idem
|
46
|
+
|
47
|
+
def workflow_idem
|
48
|
+
UUID.v5(metadata.workflow_id.to_s, metadata.id.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
def headers
|
52
|
+
metadata.headers
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_reader :client, :metadata
|
58
|
+
|
59
|
+
def task_token
|
60
|
+
metadata.task_token
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'cadence/client'
|
2
|
+
require 'cadence/thread_pool'
|
3
|
+
require 'cadence/middleware/chain'
|
4
|
+
require 'cadence/activity/task_processor'
|
5
|
+
|
6
|
+
module Cadence
|
7
|
+
class Activity
|
8
|
+
class Poller
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
thread_pool_size: 20
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
def initialize(domain, task_list, activity_lookup, middleware = [], options = {})
|
14
|
+
@domain = domain
|
15
|
+
@task_list = task_list
|
16
|
+
@activity_lookup = activity_lookup
|
17
|
+
@middleware = middleware
|
18
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
19
|
+
@shutting_down = false
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
@shutting_down = false
|
24
|
+
@thread = Thread.new(&method(:poll_loop))
|
25
|
+
end
|
26
|
+
|
27
|
+
def stop
|
28
|
+
@shutting_down = true
|
29
|
+
Cadence.logger.info('Shutting down activity poller')
|
30
|
+
end
|
31
|
+
|
32
|
+
def wait
|
33
|
+
thread.join
|
34
|
+
thread_pool.shutdown
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :domain, :task_list, :activity_lookup, :middleware, :options, :thread
|
40
|
+
|
41
|
+
def client
|
42
|
+
@client ||= Cadence::Client.generate(options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def shutting_down?
|
46
|
+
@shutting_down
|
47
|
+
end
|
48
|
+
|
49
|
+
def poll_loop
|
50
|
+
last_poll_time = Time.now
|
51
|
+
metrics_tags = { domain: domain, task_list: task_list }.freeze
|
52
|
+
|
53
|
+
loop do
|
54
|
+
thread_pool.wait_for_available_threads
|
55
|
+
|
56
|
+
return if shutting_down?
|
57
|
+
|
58
|
+
time_diff_ms = ((Time.now - last_poll_time) * 1000).round
|
59
|
+
Cadence.metrics.timing('activity_poller.time_since_last_poll', time_diff_ms, metrics_tags)
|
60
|
+
Cadence.logger.debug("Polling for activity tasks (#{domain} / #{task_list})")
|
61
|
+
|
62
|
+
task = poll_for_task
|
63
|
+
last_poll_time = Time.now
|
64
|
+
next unless task&.activityId
|
65
|
+
|
66
|
+
thread_pool.schedule { process(task) }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def poll_for_task
|
71
|
+
client.poll_for_activity_task(domain: domain, task_list: task_list)
|
72
|
+
rescue StandardError => error
|
73
|
+
Cadence.logger.error("Unable to poll for an activity task: #{error.inspect}")
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def process(task)
|
78
|
+
client = Cadence::Client.generate
|
79
|
+
middleware_chain = Middleware::Chain.new(middleware)
|
80
|
+
|
81
|
+
TaskProcessor.new(task, domain, activity_lookup, client, middleware_chain).process
|
82
|
+
end
|
83
|
+
|
84
|
+
def thread_pool
|
85
|
+
@thread_pool ||= ThreadPool.new(options[:thread_pool_size])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'cadence/metadata'
|
2
|
+
require 'cadence/activity/context'
|
3
|
+
require 'cadence/json'
|
4
|
+
|
5
|
+
module Cadence
|
6
|
+
class Activity
|
7
|
+
class TaskProcessor
|
8
|
+
def initialize(task, domain, activity_lookup, client, middleware_chain)
|
9
|
+
@task = task
|
10
|
+
@domain = domain
|
11
|
+
@task_token = task.taskToken
|
12
|
+
@activity_name = task.activityType.name
|
13
|
+
@activity_class = activity_lookup.find(activity_name)
|
14
|
+
@client = client
|
15
|
+
@middleware_chain = middleware_chain
|
16
|
+
end
|
17
|
+
|
18
|
+
def process
|
19
|
+
start_time = Time.now
|
20
|
+
|
21
|
+
Cadence.logger.info("Processing activity task for #{activity_name}")
|
22
|
+
Cadence.metrics.timing('activity_task.queue_time', queue_time_ms, activity: activity_name)
|
23
|
+
|
24
|
+
if !activity_class
|
25
|
+
respond_failed('ActivityNotRegistered', 'Activity is not registered with this worker')
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
metadata = Metadata.generate(Metadata::ACTIVITY_TYPE, task, domain)
|
30
|
+
context = Activity::Context.new(client, metadata)
|
31
|
+
|
32
|
+
result = middleware_chain.invoke(metadata) do
|
33
|
+
activity_class.execute_in_context(context, JSON.deserialize(task.input))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Do not complete asynchronous activities, these should be completed manually
|
37
|
+
respond_completed(result) unless context.async?
|
38
|
+
rescue StandardError, ScriptError => error
|
39
|
+
respond_failed(error.class.name, error.message)
|
40
|
+
rescue Exception => error
|
41
|
+
Cadence.logger.fatal("Activity #{activity_name} unexpectedly failed with: #{error.inspect}")
|
42
|
+
Cadence.logger.debug(error.backtrace.join("\n"))
|
43
|
+
raise
|
44
|
+
ensure
|
45
|
+
time_diff_ms = ((Time.now - start_time) * 1000).round
|
46
|
+
Cadence.metrics.timing('activity_task.latency', time_diff_ms, activity: activity_name)
|
47
|
+
Cadence.logger.debug("Activity task processed in #{time_diff_ms}ms")
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
attr_reader :task, :domain, :task_token, :activity_name, :activity_class, :client, :middleware_chain
|
53
|
+
|
54
|
+
def queue_time_ms
|
55
|
+
((task.startedTimestamp - task.scheduledTimestampOfThisAttempt) / 1_000_000).round
|
56
|
+
end
|
57
|
+
|
58
|
+
def respond_completed(result)
|
59
|
+
Cadence.logger.info("Activity #{activity_name} completed")
|
60
|
+
client.respond_activity_task_completed(task_token: task_token, result: result)
|
61
|
+
rescue StandardError => error
|
62
|
+
Cadence.logger.error("Unable to complete Activity #{activity_name}: #{error.inspect}")
|
63
|
+
end
|
64
|
+
|
65
|
+
def respond_failed(reason, details)
|
66
|
+
Cadence.logger.error("Activity #{activity_name} failed with: #{reason}")
|
67
|
+
client.respond_activity_task_failed(task_token: task_token, reason: reason, details: details)
|
68
|
+
rescue StandardError => error
|
69
|
+
Cadence.logger.error("Unable to fail Activity #{activity_name}: #{error.inspect}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|