temporalio 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +2 -0
- data/Cargo.lock +659 -370
- data/Cargo.toml +2 -2
- data/Gemfile +3 -3
- data/README.md +589 -47
- data/Rakefile +10 -296
- data/ext/Cargo.toml +1 -0
- data/lib/temporalio/activity/complete_async_error.rb +1 -1
- data/lib/temporalio/activity/context.rb +5 -2
- data/lib/temporalio/activity/definition.rb +163 -65
- data/lib/temporalio/activity/info.rb +22 -21
- data/lib/temporalio/activity.rb +2 -59
- data/lib/temporalio/api/activity/v1/message.rb +25 -0
- data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +34 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
- data/lib/temporalio/api/cloud/identity/v1/message.rb +6 -1
- data/lib/temporalio/api/cloud/namespace/v1/message.rb +8 -1
- data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
- data/lib/temporalio/api/cloud/operation/v1/message.rb +2 -1
- data/lib/temporalio/api/cloud/region/v1/message.rb +2 -1
- data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
- data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
- data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
- data/lib/temporalio/api/common/v1/message.rb +7 -1
- data/lib/temporalio/api/enums/v1/event_type.rb +1 -1
- data/lib/temporalio/api/enums/v1/failed_cause.rb +1 -1
- data/lib/temporalio/api/enums/v1/reset.rb +1 -1
- data/lib/temporalio/api/history/v1/message.rb +1 -1
- data/lib/temporalio/api/nexus/v1/message.rb +2 -2
- data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
- data/lib/temporalio/api/payload_visitor.rb +1513 -0
- data/lib/temporalio/api/schedule/v1/message.rb +2 -1
- data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
- data/lib/temporalio/api/testservice/v1/service.rb +23 -0
- data/lib/temporalio/api/workflow/v1/message.rb +1 -1
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +17 -2
- data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
- data/lib/temporalio/api.rb +1 -0
- data/lib/temporalio/cancellation.rb +34 -14
- data/lib/temporalio/client/async_activity_handle.rb +12 -37
- data/lib/temporalio/client/connection/cloud_service.rb +309 -231
- data/lib/temporalio/client/connection/operator_service.rb +36 -84
- data/lib/temporalio/client/connection/service.rb +6 -5
- data/lib/temporalio/client/connection/test_service.rb +111 -0
- data/lib/temporalio/client/connection/workflow_service.rb +264 -441
- data/lib/temporalio/client/connection.rb +90 -44
- data/lib/temporalio/client/interceptor.rb +160 -60
- data/lib/temporalio/client/schedule.rb +967 -0
- data/lib/temporalio/client/schedule_handle.rb +126 -0
- data/lib/temporalio/client/workflow_execution.rb +7 -10
- data/lib/temporalio/client/workflow_handle.rb +38 -95
- data/lib/temporalio/client/workflow_update_handle.rb +3 -5
- data/lib/temporalio/client.rb +122 -42
- data/lib/temporalio/common_enums.rb +17 -0
- data/lib/temporalio/converters/data_converter.rb +4 -7
- data/lib/temporalio/converters/failure_converter.rb +5 -3
- data/lib/temporalio/converters/payload_converter/composite.rb +4 -0
- data/lib/temporalio/converters/payload_converter.rb +6 -8
- data/lib/temporalio/converters/raw_value.rb +20 -0
- data/lib/temporalio/error/failure.rb +1 -1
- data/lib/temporalio/error.rb +10 -2
- data/lib/temporalio/internal/bridge/api/core_interface.rb +5 -1
- data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +5 -1
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +4 -1
- data/lib/temporalio/internal/bridge/client.rb +11 -6
- data/lib/temporalio/internal/bridge/testing.rb +20 -0
- data/lib/temporalio/internal/bridge/worker.rb +2 -0
- data/lib/temporalio/internal/bridge.rb +1 -1
- data/lib/temporalio/internal/client/implementation.rb +245 -70
- data/lib/temporalio/internal/metric.rb +122 -0
- data/lib/temporalio/internal/proto_utils.rb +86 -7
- data/lib/temporalio/internal/worker/activity_worker.rb +52 -24
- data/lib/temporalio/internal/worker/multi_runner.rb +51 -7
- data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +329 -0
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +44 -0
- data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
- data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
- data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +415 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +163 -0
- data/lib/temporalio/internal/worker/workflow_instance.rb +730 -0
- data/lib/temporalio/internal/worker/workflow_worker.rb +196 -0
- data/lib/temporalio/metric.rb +109 -0
- data/lib/temporalio/retry_policy.rb +37 -14
- data/lib/temporalio/runtime.rb +118 -75
- data/lib/temporalio/search_attributes.rb +80 -37
- data/lib/temporalio/testing/activity_environment.rb +2 -2
- data/lib/temporalio/testing/workflow_environment.rb +251 -5
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/activity_executor/thread_pool.rb +9 -217
- data/lib/temporalio/worker/activity_executor.rb +3 -3
- data/lib/temporalio/worker/interceptor.rb +340 -66
- data/lib/temporalio/worker/thread_pool.rb +237 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +230 -0
- data/lib/temporalio/worker/workflow_executor.rb +26 -0
- data/lib/temporalio/worker.rb +201 -30
- data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
- data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
- data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
- data/lib/temporalio/workflow/definition.rb +566 -0
- data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
- data/lib/temporalio/workflow/future.rb +151 -0
- data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
- data/lib/temporalio/workflow/info.rb +82 -0
- data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
- data/lib/temporalio/workflow/update_info.rb +20 -0
- data/lib/temporalio/workflow.rb +523 -0
- data/lib/temporalio.rb +4 -0
- data/temporalio.gemspec +2 -2
- metadata +50 -8
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require 'temporalio/internal/bridge'
|
5
|
+
require 'temporalio/metric'
|
6
|
+
|
7
|
+
module Temporalio
|
8
|
+
module Internal
|
9
|
+
class Metric < Temporalio::Metric
|
10
|
+
attr_reader :metric_type, :name, :description, :unit, :value_type
|
11
|
+
|
12
|
+
def initialize(metric_type:, name:, description:, unit:, value_type:, bridge:, bridge_attrs:) # rubocop:disable Lint/MissingSuper
|
13
|
+
@metric_type = metric_type
|
14
|
+
@name = name
|
15
|
+
@description = description
|
16
|
+
@unit = unit
|
17
|
+
@value_type = value_type
|
18
|
+
@bridge = bridge
|
19
|
+
@bridge_attrs = bridge_attrs
|
20
|
+
end
|
21
|
+
|
22
|
+
def record(value, additional_attributes: nil)
|
23
|
+
bridge_attrs = @bridge_attrs
|
24
|
+
bridge_attrs = @bridge_attrs.with_additional(additional_attributes) if additional_attributes
|
25
|
+
@bridge.record_value(value, bridge_attrs)
|
26
|
+
end
|
27
|
+
|
28
|
+
def with_additional_attributes(additional_attributes)
|
29
|
+
Metric.new(
|
30
|
+
metric_type:,
|
31
|
+
name:,
|
32
|
+
description:,
|
33
|
+
unit:,
|
34
|
+
value_type:,
|
35
|
+
bridge: @bridge,
|
36
|
+
bridge_attrs: @bridge_attrs.with_additional(additional_attributes)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
class Meter < Temporalio::Metric::Meter
|
41
|
+
def self.create_from_runtime(runtime)
|
42
|
+
bridge = Bridge::Metric::Meter.new(runtime._core_runtime)
|
43
|
+
return nil unless bridge
|
44
|
+
|
45
|
+
Meter.new(bridge, bridge.default_attributes)
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(bridge, bridge_attrs) # rubocop:disable Lint/MissingSuper
|
49
|
+
@bridge = bridge
|
50
|
+
@bridge_attrs = bridge_attrs
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_metric(
|
54
|
+
metric_type,
|
55
|
+
name,
|
56
|
+
description: nil,
|
57
|
+
unit: nil,
|
58
|
+
value_type: :integer
|
59
|
+
)
|
60
|
+
Metric.new(
|
61
|
+
metric_type:,
|
62
|
+
name:,
|
63
|
+
description:,
|
64
|
+
unit:,
|
65
|
+
value_type:,
|
66
|
+
bridge: Bridge::Metric.new(@bridge, metric_type, name, description, unit, value_type),
|
67
|
+
bridge_attrs: @bridge_attrs
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def with_additional_attributes(additional_attributes)
|
72
|
+
Meter.new(@bridge, @bridge_attrs.with_additional(additional_attributes))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class NullMeter < Temporalio::Metric::Meter
|
77
|
+
include Singleton
|
78
|
+
|
79
|
+
def initialize # rubocop:disable Style/RedundantInitialize,Lint/MissingSuper
|
80
|
+
end
|
81
|
+
|
82
|
+
def create_metric(
|
83
|
+
metric_type,
|
84
|
+
name,
|
85
|
+
description: nil,
|
86
|
+
unit: nil,
|
87
|
+
value_type: :integer
|
88
|
+
)
|
89
|
+
NullMetric.new(
|
90
|
+
metric_type:,
|
91
|
+
name:,
|
92
|
+
description:,
|
93
|
+
unit:,
|
94
|
+
value_type:
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
def with_additional_attributes(_additional_attributes)
|
99
|
+
self
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class NullMetric < Temporalio::Metric
|
104
|
+
attr_reader :metric_type, :name, :description, :unit, :value_type
|
105
|
+
|
106
|
+
def initialize(metric_type:, name:, description:, unit:, value_type:) # rubocop:disable Lint/MissingSuper
|
107
|
+
@metric_type = metric_type
|
108
|
+
@name = name
|
109
|
+
@description = description
|
110
|
+
@unit = unit
|
111
|
+
@value_type = value_type
|
112
|
+
end
|
113
|
+
|
114
|
+
def record(value, additional_attributes: nil); end
|
115
|
+
|
116
|
+
def with_additional_attributes(_additional_attributes)
|
117
|
+
self
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -5,26 +5,82 @@ require 'temporalio/api'
|
|
5
5
|
module Temporalio
|
6
6
|
module Internal
|
7
7
|
module ProtoUtils
|
8
|
-
def self.seconds_to_duration(
|
9
|
-
return nil if
|
8
|
+
def self.seconds_to_duration(seconds_numeric)
|
9
|
+
return nil if seconds_numeric.nil?
|
10
10
|
|
11
|
-
seconds =
|
12
|
-
nanos = ((
|
11
|
+
seconds = seconds_numeric.to_i
|
12
|
+
nanos = ((seconds_numeric - seconds) * 1_000_000_000).round
|
13
13
|
Google::Protobuf::Duration.new(seconds:, nanos:)
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.duration_to_seconds(duration)
|
17
|
+
return nil if duration.nil?
|
18
|
+
|
19
|
+
# This logic was corrected for timestamp at
|
20
|
+
# https://github.com/protocolbuffers/protobuf/pull/2482 but not for
|
21
|
+
# duration, so 4.56 is not properly represented in to_f, it becomes
|
22
|
+
# 4.5600000000000005.
|
23
|
+
(duration.seconds + duration.nanos.quo(1_000_000_000)).to_f
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.time_to_timestamp(time)
|
27
|
+
return nil if time.nil?
|
28
|
+
|
29
|
+
Google::Protobuf::Timestamp.from_time(time)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.timestamp_to_time(timestamp)
|
33
|
+
return nil if timestamp.nil?
|
34
|
+
|
35
|
+
# The regular to_time on the timestamp converts to local timezone,
|
36
|
+
# and we prefer not to make a separate .utc call (converts to local
|
37
|
+
# then back to UTC unnecessarily)
|
38
|
+
Time.at(timestamp.seconds, timestamp.nanos, :nanosecond, in: 'UTC')
|
39
|
+
end
|
40
|
+
|
16
41
|
def self.memo_to_proto(hash, converter)
|
17
|
-
return nil if hash.nil?
|
42
|
+
return nil if hash.nil? || hash.empty?
|
43
|
+
|
44
|
+
Api::Common::V1::Memo.new(fields: memo_to_proto_hash(hash, converter))
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.memo_to_proto_hash(hash, converter)
|
48
|
+
return nil if hash.nil? || hash.empty?
|
18
49
|
|
19
|
-
|
50
|
+
hash.transform_keys(&:to_s).transform_values { |val| converter.to_payload(val) }
|
20
51
|
end
|
21
52
|
|
22
53
|
def self.memo_from_proto(memo, converter)
|
23
|
-
return nil if memo.nil?
|
54
|
+
return nil if memo.nil? || memo.fields.size.zero? # rubocop:disable Style/ZeroLengthPredicate Google Maps don't have empty
|
24
55
|
|
25
56
|
memo.fields.each_with_object({}) { |(key, val), h| h[key] = converter.from_payload(val) } # rubocop:disable Style/HashTransformValues
|
26
57
|
end
|
27
58
|
|
59
|
+
def self.headers_to_proto(headers, converter)
|
60
|
+
return nil if headers.nil? || headers.empty?
|
61
|
+
|
62
|
+
Api::Common::V1::Header.new(fields: headers_to_proto_hash(headers, converter))
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.headers_to_proto_hash(headers, converter)
|
66
|
+
return nil if headers.nil? || headers.empty?
|
67
|
+
|
68
|
+
headers.transform_values { |val| converter.to_payload(val) }
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.headers_from_proto(headers, converter)
|
72
|
+
headers_from_proto_map(headers&.fields, converter)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.headers_from_proto_map(headers, converter)
|
76
|
+
return nil if headers.nil? || headers.size.zero? # rubocop:disable Style/ZeroLengthPredicate Google Maps don't have empty
|
77
|
+
|
78
|
+
headers.each_with_object({}) do |(key, val), h| # rubocop:disable Style/HashTransformValues
|
79
|
+
# @type var h: Hash[String, Object?]
|
80
|
+
h[key] = converter.from_payload(val)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
28
84
|
def self.string_or(str, default = nil)
|
29
85
|
str && !str.empty? ? str : default
|
30
86
|
end
|
@@ -49,6 +105,29 @@ module Temporalio
|
|
49
105
|
|
50
106
|
converter.to_payloads(values).payloads.to_ary
|
51
107
|
end
|
108
|
+
|
109
|
+
class LazyMemo
|
110
|
+
def initialize(raw_memo, converter)
|
111
|
+
@raw_memo = raw_memo
|
112
|
+
@converter = converter
|
113
|
+
end
|
114
|
+
|
115
|
+
def get
|
116
|
+
@memo = ProtoUtils.memo_from_proto(@raw_memo, @converter) unless defined?(@memo)
|
117
|
+
@memo
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class LazySearchAttributes
|
122
|
+
def initialize(raw_search_attributes)
|
123
|
+
@raw_search_attributes = raw_search_attributes
|
124
|
+
end
|
125
|
+
|
126
|
+
def get
|
127
|
+
@search_attributes = SearchAttributes._from_proto(@raw_search_attributes) unless defined?(@search_attributes)
|
128
|
+
@search_attributes
|
129
|
+
end
|
130
|
+
end
|
52
131
|
end
|
53
132
|
end
|
54
133
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'temporalio/activity'
|
4
4
|
require 'temporalio/activity/definition'
|
5
5
|
require 'temporalio/cancellation'
|
6
|
+
require 'temporalio/converters/raw_value'
|
6
7
|
require 'temporalio/internal/bridge/api'
|
7
8
|
require 'temporalio/internal/proto_utils'
|
8
9
|
require 'temporalio/scoped_logger'
|
@@ -11,14 +12,17 @@ require 'temporalio/worker/interceptor'
|
|
11
12
|
module Temporalio
|
12
13
|
module Internal
|
13
14
|
module Worker
|
15
|
+
# Worker for handling activity tasks. Upon overarching worker shutdown, {wait_all_complete} should be used to wait
|
16
|
+
# for the activities to complete.
|
14
17
|
class ActivityWorker
|
15
18
|
LOG_TASKS = false
|
16
19
|
|
17
20
|
attr_reader :worker, :bridge_worker
|
18
21
|
|
19
|
-
def initialize(worker
|
22
|
+
def initialize(worker:, bridge_worker:)
|
20
23
|
@worker = worker
|
21
24
|
@bridge_worker = bridge_worker
|
25
|
+
@runtime_metric_meter = worker.options.client.connection.options.runtime.metric_meter
|
22
26
|
|
23
27
|
# Create shared logger that gives scoped activity details
|
24
28
|
@scoped_logger = ScopedLogger.new(@worker.options.logger)
|
@@ -26,12 +30,13 @@ module Temporalio
|
|
26
30
|
Activity::Context.current_or_nil&._scoped_logger_info
|
27
31
|
}
|
28
32
|
|
29
|
-
# Build up activity hash by name, failing if any fail validation
|
33
|
+
# Build up activity hash by name (can be nil for dynamic), failing if any fail validation
|
30
34
|
@activities = worker.options.activities.each_with_object({}) do |act, hash|
|
31
35
|
# Class means create each time, instance means just call, definition
|
32
36
|
# does nothing special
|
33
|
-
defn = Activity::Definition.from_activity(act)
|
37
|
+
defn = Activity::Definition::Info.from_activity(act)
|
34
38
|
# Confirm name not in use
|
39
|
+
raise ArgumentError, 'Only one dynamic activity allowed' if !defn.name && hash.key?(defn.name)
|
35
40
|
raise ArgumentError, "Multiple activities named #{defn.name}" if hash.key?(defn.name)
|
36
41
|
|
37
42
|
# Confirm executor is a known executor and let it initialize
|
@@ -88,8 +93,8 @@ module Temporalio
|
|
88
93
|
def handle_start_task(task_token, start)
|
89
94
|
set_running_activity(task_token, nil)
|
90
95
|
|
91
|
-
# Find activity definition
|
92
|
-
defn = @activities[start.activity_type]
|
96
|
+
# Find activity definition, falling back to dynamic if present
|
97
|
+
defn = @activities[start.activity_type] || @activities[nil]
|
93
98
|
if defn.nil?
|
94
99
|
raise Error::ApplicationError.new(
|
95
100
|
"Activity #{start.activity_type} for workflow #{start.workflow_execution.workflow_id} " \
|
@@ -158,17 +163,19 @@ module Temporalio
|
|
158
163
|
activity_id: start.activity_id,
|
159
164
|
activity_type: start.activity_type,
|
160
165
|
attempt: start.attempt,
|
161
|
-
current_attempt_scheduled_time:
|
166
|
+
current_attempt_scheduled_time: Internal::ProtoUtils.timestamp_to_time(
|
167
|
+
start.current_attempt_scheduled_time
|
168
|
+
) || raise, # Never nil
|
162
169
|
heartbeat_details: ProtoUtils.convert_from_payload_array(
|
163
170
|
@worker.options.client.data_converter,
|
164
171
|
start.heartbeat_details.to_ary
|
165
172
|
),
|
166
|
-
heartbeat_timeout: start.heartbeat_timeout
|
173
|
+
heartbeat_timeout: Internal::ProtoUtils.duration_to_seconds(start.heartbeat_timeout),
|
167
174
|
local?: start.is_local,
|
168
|
-
schedule_to_close_timeout: start.schedule_to_close_timeout
|
169
|
-
scheduled_time: start.scheduled_time
|
170
|
-
start_to_close_timeout: start.start_to_close_timeout
|
171
|
-
started_time: start.started_time
|
175
|
+
schedule_to_close_timeout: Internal::ProtoUtils.duration_to_seconds(start.schedule_to_close_timeout),
|
176
|
+
scheduled_time: Internal::ProtoUtils.timestamp_to_time(start.scheduled_time) || raise, # Never nil
|
177
|
+
start_to_close_timeout: Internal::ProtoUtils.duration_to_seconds(start.start_to_close_timeout),
|
178
|
+
started_time: Internal::ProtoUtils.timestamp_to_time(start.started_time) || raise, # Never nil
|
172
179
|
task_queue: @worker.options.task_queue,
|
173
180
|
task_token:,
|
174
181
|
workflow_id: start.workflow_execution.workflow_id,
|
@@ -178,13 +185,18 @@ module Temporalio
|
|
178
185
|
).freeze
|
179
186
|
|
180
187
|
# Build input
|
181
|
-
input = Temporalio::Worker::Interceptor::
|
188
|
+
input = Temporalio::Worker::Interceptor::Activity::ExecuteInput.new(
|
182
189
|
proc: defn.proc,
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
190
|
+
# If the activity wants raw_args, we only decode we don't convert
|
191
|
+
args: if defn.raw_args
|
192
|
+
payloads = start.input.to_ary
|
193
|
+
codec = @worker.options.client.data_converter.payload_codec
|
194
|
+
payloads = codec.decode(payloads) if codec
|
195
|
+
payloads.map { |p| Temporalio::Converters::RawValue.new(p) }
|
196
|
+
else
|
197
|
+
ProtoUtils.convert_from_payload_array(@worker.options.client.data_converter, start.input.to_ary)
|
198
|
+
end,
|
199
|
+
headers: ProtoUtils.headers_from_proto_map(start.header_fields, @worker.options.client.data_converter) || {}
|
188
200
|
)
|
189
201
|
|
190
202
|
# Run
|
@@ -193,7 +205,8 @@ module Temporalio
|
|
193
205
|
cancellation: Cancellation.new,
|
194
206
|
worker_shutdown_cancellation: @worker._worker_shutdown_cancellation,
|
195
207
|
payload_converter: @worker.options.client.data_converter.payload_converter,
|
196
|
-
logger: @scoped_logger
|
208
|
+
logger: @scoped_logger,
|
209
|
+
runtime_metric_meter: @runtime_metric_meter
|
197
210
|
)
|
198
211
|
Activity::Context._current_executor&.set_activity_context(defn, activity)
|
199
212
|
set_running_activity(task_token, activity)
|
@@ -226,9 +239,9 @@ module Temporalio
|
|
226
239
|
def run_activity(activity, input)
|
227
240
|
result = begin
|
228
241
|
# Build impl with interceptors
|
229
|
-
# @type var impl: Temporalio::Worker::Interceptor::
|
242
|
+
# @type var impl: Temporalio::Worker::Interceptor::Activity::Inbound
|
230
243
|
impl = InboundImplementation.new(self)
|
231
|
-
impl = @worker.
|
244
|
+
impl = @worker._activity_interceptors.reverse_each.reduce(impl) do |acc, int|
|
232
245
|
int.intercept_activity(acc)
|
233
246
|
end
|
234
247
|
impl.init(OutboundImplementation.new(self))
|
@@ -287,13 +300,15 @@ module Temporalio
|
|
287
300
|
cancellation:,
|
288
301
|
worker_shutdown_cancellation:,
|
289
302
|
payload_converter:,
|
290
|
-
logger
|
303
|
+
logger:,
|
304
|
+
runtime_metric_meter:
|
291
305
|
)
|
292
306
|
@info = info
|
293
307
|
@cancellation = cancellation
|
294
308
|
@worker_shutdown_cancellation = worker_shutdown_cancellation
|
295
309
|
@payload_converter = payload_converter
|
296
310
|
@logger = logger
|
311
|
+
@runtime_metric_meter = runtime_metric_meter
|
297
312
|
@_outbound_impl = nil
|
298
313
|
@_server_requested_cancel = false
|
299
314
|
end
|
@@ -301,11 +316,24 @@ module Temporalio
|
|
301
316
|
def heartbeat(*details)
|
302
317
|
raise 'Implementation not set yet' if _outbound_impl.nil?
|
303
318
|
|
304
|
-
|
319
|
+
# No-op if local
|
320
|
+
return if info.local?
|
321
|
+
|
322
|
+
_outbound_impl.heartbeat(Temporalio::Worker::Interceptor::Activity::HeartbeatInput.new(details:))
|
323
|
+
end
|
324
|
+
|
325
|
+
def metric_meter
|
326
|
+
@metric_meter ||= @runtime_metric_meter.with_additional_attributes(
|
327
|
+
{
|
328
|
+
namespace: info.workflow_namespace,
|
329
|
+
task_queue: info.task_queue,
|
330
|
+
activity_type: info.activity_type
|
331
|
+
}
|
332
|
+
)
|
305
333
|
end
|
306
334
|
end
|
307
335
|
|
308
|
-
class InboundImplementation < Temporalio::Worker::Interceptor::
|
336
|
+
class InboundImplementation < Temporalio::Worker::Interceptor::Activity::Inbound
|
309
337
|
def initialize(worker)
|
310
338
|
super(nil) # steep:ignore
|
311
339
|
@worker = worker
|
@@ -323,7 +351,7 @@ module Temporalio
|
|
323
351
|
end
|
324
352
|
end
|
325
353
|
|
326
|
-
class OutboundImplementation < Temporalio::Worker::Interceptor::
|
354
|
+
class OutboundImplementation < Temporalio::Worker::Interceptor::Activity::Outbound
|
327
355
|
def initialize(worker)
|
328
356
|
super(nil) # steep:ignore
|
329
357
|
@worker = worker
|
@@ -6,6 +6,8 @@ require 'temporalio/internal/bridge/worker'
|
|
6
6
|
module Temporalio
|
7
7
|
module Internal
|
8
8
|
module Worker
|
9
|
+
# Primary worker (re)actor-style event handler. This handles multiple workers, receiving events from the bridge,
|
10
|
+
# and handling a user block.
|
9
11
|
class MultiRunner
|
10
12
|
def initialize(workers:, shutdown_signals:)
|
11
13
|
@workers = workers
|
@@ -47,6 +49,16 @@ module Temporalio
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
52
|
+
def apply_workflow_activation_decoded(workflow_worker:, activation:)
|
53
|
+
@queue.push(Event::WorkflowActivationDecoded.new(workflow_worker:, activation:))
|
54
|
+
end
|
55
|
+
|
56
|
+
def apply_workflow_activation_complete(workflow_worker:, activation_completion:, encoded:)
|
57
|
+
@queue.push(Event::WorkflowActivationComplete.new(
|
58
|
+
workflow_worker:, activation_completion:, encoded:, completion_complete_queue: @queue
|
59
|
+
))
|
60
|
+
end
|
61
|
+
|
50
62
|
def raise_in_thread_or_fiber_block(error)
|
51
63
|
@thread_or_fiber&.raise(error)
|
52
64
|
end
|
@@ -80,22 +92,25 @@ module Temporalio
|
|
80
92
|
# * [worker index, :activity/:workflow, error] - poll fail
|
81
93
|
# * [worker index, :activity/:workflow, nil] - worker shutdown
|
82
94
|
# * [nil, nil, nil] - all pollers done
|
95
|
+
# * [-1, run_id_string, error_or_nil] - workflow activation completion complete
|
83
96
|
result = @queue.pop
|
84
97
|
if result.is_a?(Event)
|
85
98
|
result
|
86
99
|
else
|
87
|
-
|
88
|
-
if
|
100
|
+
first, second, third = result
|
101
|
+
if first.nil? || second.nil?
|
89
102
|
Event::AllPollersShutDown.instance
|
103
|
+
elsif first == -1
|
104
|
+
Event::WorkflowActivationCompletionComplete.new(run_id: second, error: third)
|
90
105
|
else
|
91
|
-
worker = @workers[
|
92
|
-
case
|
106
|
+
worker = @workers[first]
|
107
|
+
case third
|
93
108
|
when nil
|
94
|
-
Event::PollerShutDown.new(worker:, worker_type:)
|
109
|
+
Event::PollerShutDown.new(worker:, worker_type: second)
|
95
110
|
when Exception
|
96
|
-
Event::PollFailure.new(worker:, worker_type
|
111
|
+
Event::PollFailure.new(worker:, worker_type: second, error: third)
|
97
112
|
else
|
98
|
-
Event::PollSuccess.new(worker:, worker_type
|
113
|
+
Event::PollSuccess.new(worker:, worker_type: second, bytes: third)
|
99
114
|
end
|
100
115
|
end
|
101
116
|
end
|
@@ -122,6 +137,35 @@ module Temporalio
|
|
122
137
|
end
|
123
138
|
end
|
124
139
|
|
140
|
+
class WorkflowActivationDecoded < Event
|
141
|
+
attr_reader :workflow_worker, :activation
|
142
|
+
|
143
|
+
def initialize(workflow_worker:, activation:) # rubocop:disable Lint/MissingSuper
|
144
|
+
@workflow_worker = workflow_worker
|
145
|
+
@activation = activation
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class WorkflowActivationComplete < Event
|
150
|
+
attr_reader :workflow_worker, :activation_completion, :encoded, :completion_complete_queue
|
151
|
+
|
152
|
+
def initialize(workflow_worker:, activation_completion:, encoded:, completion_complete_queue:) # rubocop:disable Lint/MissingSuper
|
153
|
+
@workflow_worker = workflow_worker
|
154
|
+
@activation_completion = activation_completion
|
155
|
+
@encoded = encoded
|
156
|
+
@completion_complete_queue = completion_complete_queue
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class WorkflowActivationCompletionComplete < Event
|
161
|
+
attr_reader :run_id, :error
|
162
|
+
|
163
|
+
def initialize(run_id:, error:) # rubocop:disable Lint/MissingSuper
|
164
|
+
@run_id = run_id
|
165
|
+
@error = error
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
125
169
|
class PollerShutDown < Event
|
126
170
|
attr_reader :worker, :worker_type
|
127
171
|
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'temporalio/cancellation'
|
4
|
+
require 'temporalio/workflow'
|
5
|
+
require 'temporalio/workflow/child_workflow_handle'
|
6
|
+
|
7
|
+
module Temporalio
|
8
|
+
module Internal
|
9
|
+
module Worker
|
10
|
+
class WorkflowInstance
|
11
|
+
# Implementation of the child workflow handle.
|
12
|
+
class ChildWorkflowHandle < Workflow::ChildWorkflowHandle
|
13
|
+
attr_reader :id, :first_execution_run_id
|
14
|
+
|
15
|
+
def initialize(id:, first_execution_run_id:, instance:, cancellation:, cancel_callback_key:) # rubocop:disable Lint/MissingSuper
|
16
|
+
@id = id
|
17
|
+
@first_execution_run_id = first_execution_run_id
|
18
|
+
@instance = instance
|
19
|
+
@cancellation = cancellation
|
20
|
+
@cancel_callback_key = cancel_callback_key
|
21
|
+
@resolution = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def result
|
25
|
+
# Notice that we actually provide a detached cancellation here instead of defaulting to workflow
|
26
|
+
# cancellation because we don't want workflow cancellation (or a user-provided cancellation to this result
|
27
|
+
# call) to be able to interrupt waiting on a child that may be processing the cancellation.
|
28
|
+
Workflow.wait_condition(cancellation: Cancellation.new) { @resolution }
|
29
|
+
|
30
|
+
case @resolution.status
|
31
|
+
when :completed
|
32
|
+
@instance.payload_converter.from_payload(@resolution.completed.result)
|
33
|
+
when :failed
|
34
|
+
raise @instance.failure_converter.from_failure(@resolution.failed.failure, @instance.payload_converter)
|
35
|
+
when :cancelled
|
36
|
+
raise @instance.failure_converter.from_failure(@resolution.cancelled.failure, @instance.payload_converter)
|
37
|
+
else
|
38
|
+
raise "Unrecognized resolution status: #{@resolution.status}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def _resolve(resolution)
|
43
|
+
@cancellation.remove_cancel_callback(@cancel_callback_key)
|
44
|
+
@resolution = resolution
|
45
|
+
end
|
46
|
+
|
47
|
+
def signal(signal, *args, cancellation: Workflow.cancellation)
|
48
|
+
@instance.context._signal_child_workflow(id:, signal:, args:, cancellation:)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|