amit-temporalio 0.3.1
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 +7 -0
- data/.yardopts +2 -0
- data/Cargo.lock +4325 -0
- data/Cargo.toml +25 -0
- data/Gemfile +23 -0
- data/LICENSE +21 -0
- data/README.md +1148 -0
- data/Rakefile +101 -0
- data/ext/Cargo.toml +27 -0
- data/lib/temporalio/activity/complete_async_error.rb +11 -0
- data/lib/temporalio/activity/context.rb +116 -0
- data/lib/temporalio/activity/definition.rb +189 -0
- data/lib/temporalio/activity/info.rb +64 -0
- data/lib/temporalio/activity.rb +12 -0
- data/lib/temporalio/api/activity/v1/message.rb +25 -0
- data/lib/temporalio/api/batch/v1/message.rb +31 -0
- data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +126 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +25 -0
- data/lib/temporalio/api/cloud/cloudservice.rb +3 -0
- data/lib/temporalio/api/cloud/identity/v1/message.rb +41 -0
- data/lib/temporalio/api/cloud/namespace/v1/message.rb +42 -0
- data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
- data/lib/temporalio/api/cloud/operation/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/region/v1/message.rb +24 -0
- 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/command/v1/message.rb +46 -0
- data/lib/temporalio/api/common/v1/grpc_status.rb +23 -0
- data/lib/temporalio/api/common/v1/message.rb +47 -0
- data/lib/temporalio/api/enums/v1/batch_operation.rb +22 -0
- data/lib/temporalio/api/enums/v1/command_type.rb +21 -0
- data/lib/temporalio/api/enums/v1/common.rb +26 -0
- data/lib/temporalio/api/enums/v1/event_type.rb +21 -0
- data/lib/temporalio/api/enums/v1/failed_cause.rb +26 -0
- data/lib/temporalio/api/enums/v1/namespace.rb +23 -0
- data/lib/temporalio/api/enums/v1/query.rb +22 -0
- data/lib/temporalio/api/enums/v1/reset.rb +23 -0
- data/lib/temporalio/api/enums/v1/schedule.rb +21 -0
- data/lib/temporalio/api/enums/v1/task_queue.rb +25 -0
- data/lib/temporalio/api/enums/v1/update.rb +22 -0
- data/lib/temporalio/api/enums/v1/workflow.rb +30 -0
- data/lib/temporalio/api/errordetails/v1/message.rb +42 -0
- data/lib/temporalio/api/export/v1/message.rb +24 -0
- data/lib/temporalio/api/failure/v1/message.rb +35 -0
- data/lib/temporalio/api/filter/v1/message.rb +27 -0
- data/lib/temporalio/api/history/v1/message.rb +90 -0
- data/lib/temporalio/api/namespace/v1/message.rb +31 -0
- data/lib/temporalio/api/nexus/v1/message.rb +40 -0
- data/lib/temporalio/api/operatorservice/v1/request_response.rb +49 -0
- data/lib/temporalio/api/operatorservice/v1/service.rb +23 -0
- data/lib/temporalio/api/operatorservice.rb +3 -0
- data/lib/temporalio/api/payload_visitor.rb +1513 -0
- data/lib/temporalio/api/protocol/v1/message.rb +23 -0
- data/lib/temporalio/api/query/v1/message.rb +27 -0
- data/lib/temporalio/api/replication/v1/message.rb +26 -0
- data/lib/temporalio/api/schedule/v1/message.rb +43 -0
- data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +25 -0
- data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +21 -0
- data/lib/temporalio/api/sdk/v1/user_metadata.rb +23 -0
- data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +23 -0
- data/lib/temporalio/api/taskqueue/v1/message.rb +45 -0
- 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/update/v1/message.rb +33 -0
- data/lib/temporalio/api/version/v1/message.rb +26 -0
- data/lib/temporalio/api/workflow/v1/message.rb +43 -0
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +204 -0
- data/lib/temporalio/api/workflowservice/v1/service.rb +23 -0
- data/lib/temporalio/api/workflowservice.rb +3 -0
- data/lib/temporalio/api.rb +14 -0
- data/lib/temporalio/cancellation.rb +170 -0
- data/lib/temporalio/client/activity_id_reference.rb +32 -0
- data/lib/temporalio/client/async_activity_handle.rb +85 -0
- data/lib/temporalio/client/connection/cloud_service.rb +726 -0
- data/lib/temporalio/client/connection/operator_service.rb +201 -0
- data/lib/temporalio/client/connection/service.rb +42 -0
- data/lib/temporalio/client/connection/test_service.rb +111 -0
- data/lib/temporalio/client/connection/workflow_service.rb +1041 -0
- data/lib/temporalio/client/connection.rb +316 -0
- data/lib/temporalio/client/interceptor.rb +416 -0
- data/lib/temporalio/client/schedule.rb +967 -0
- data/lib/temporalio/client/schedule_handle.rb +126 -0
- data/lib/temporalio/client/workflow_execution.rb +100 -0
- data/lib/temporalio/client/workflow_execution_count.rb +36 -0
- data/lib/temporalio/client/workflow_execution_status.rb +18 -0
- data/lib/temporalio/client/workflow_handle.rb +389 -0
- data/lib/temporalio/client/workflow_query_reject_condition.rb +14 -0
- data/lib/temporalio/client/workflow_update_handle.rb +65 -0
- data/lib/temporalio/client/workflow_update_wait_stage.rb +17 -0
- data/lib/temporalio/client.rb +484 -0
- data/lib/temporalio/common_enums.rb +41 -0
- data/lib/temporalio/converters/data_converter.rb +99 -0
- data/lib/temporalio/converters/failure_converter.rb +202 -0
- data/lib/temporalio/converters/payload_codec.rb +26 -0
- data/lib/temporalio/converters/payload_converter/binary_null.rb +34 -0
- data/lib/temporalio/converters/payload_converter/binary_plain.rb +35 -0
- data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +42 -0
- data/lib/temporalio/converters/payload_converter/composite.rb +66 -0
- data/lib/temporalio/converters/payload_converter/encoding.rb +35 -0
- data/lib/temporalio/converters/payload_converter/json_plain.rb +44 -0
- data/lib/temporalio/converters/payload_converter/json_protobuf.rb +41 -0
- data/lib/temporalio/converters/payload_converter.rb +71 -0
- data/lib/temporalio/converters/raw_value.rb +20 -0
- data/lib/temporalio/converters.rb +9 -0
- data/lib/temporalio/error/failure.rb +219 -0
- data/lib/temporalio/error.rb +155 -0
- data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +34 -0
- data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +31 -0
- data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +33 -0
- data/lib/temporalio/internal/bridge/api/common/common.rb +26 -0
- data/lib/temporalio/internal/bridge/api/core_interface.rb +40 -0
- data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +27 -0
- data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +56 -0
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +57 -0
- data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +30 -0
- data/lib/temporalio/internal/bridge/api.rb +3 -0
- data/lib/temporalio/internal/bridge/client.rb +95 -0
- data/lib/temporalio/internal/bridge/runtime.rb +53 -0
- data/lib/temporalio/internal/bridge/testing.rb +66 -0
- data/lib/temporalio/internal/bridge/worker.rb +85 -0
- data/lib/temporalio/internal/bridge.rb +36 -0
- data/lib/temporalio/internal/client/implementation.rb +700 -0
- data/lib/temporalio/internal/metric.rb +122 -0
- data/lib/temporalio/internal/proto_utils.rb +133 -0
- data/lib/temporalio/internal/worker/activity_worker.rb +376 -0
- data/lib/temporalio/internal/worker/multi_runner.rb +213 -0
- data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +333 -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 +236 -0
- data/lib/temporalio/internal.rb +7 -0
- data/lib/temporalio/metric.rb +109 -0
- data/lib/temporalio/retry_policy.rb +74 -0
- data/lib/temporalio/runtime.rb +314 -0
- data/lib/temporalio/scoped_logger.rb +96 -0
- data/lib/temporalio/search_attributes.rb +343 -0
- data/lib/temporalio/testing/activity_environment.rb +136 -0
- data/lib/temporalio/testing/workflow_environment.rb +383 -0
- data/lib/temporalio/testing.rb +10 -0
- data/lib/temporalio/version.rb +5 -0
- data/lib/temporalio/worker/activity_executor/fiber.rb +49 -0
- data/lib/temporalio/worker/activity_executor/thread_pool.rb +46 -0
- data/lib/temporalio/worker/activity_executor.rb +55 -0
- data/lib/temporalio/worker/interceptor.rb +362 -0
- data/lib/temporalio/worker/thread_pool.rb +237 -0
- data/lib/temporalio/worker/tuner.rb +189 -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/workflow_replayer.rb +343 -0
- data/lib/temporalio/worker.rb +569 -0
- 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 +529 -0
- data/lib/temporalio/workflow_history.rb +47 -0
- data/lib/temporalio.rb +11 -0
- data/temporalio.gemspec +28 -0
- metadata +234 -0
@@ -0,0 +1,362 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Temporalio
|
4
|
+
class Worker
|
5
|
+
module Interceptor
|
6
|
+
# Mixin for intercepting activity worker work. Clases that `include` may implement their own {intercept_activity}
|
7
|
+
# that returns their own instance of {Inbound}.
|
8
|
+
#
|
9
|
+
# @note Input classes herein may get new required fields added and therefore the constructors of the Input classes
|
10
|
+
# may change in backwards incompatible ways. Users should not try to construct Input classes themselves.
|
11
|
+
module Activity
|
12
|
+
# Method called when intercepting an activity. This is called when starting an activity attempt.
|
13
|
+
#
|
14
|
+
# @param next_interceptor [Inbound] Next interceptor in the chain that should be called. This is usually passed
|
15
|
+
# to {Inbound} constructor.
|
16
|
+
# @return [Inbound] Interceptor to be called for activity calls.
|
17
|
+
def intercept_activity(next_interceptor)
|
18
|
+
next_interceptor
|
19
|
+
end
|
20
|
+
|
21
|
+
# Input for {Inbound.execute}.
|
22
|
+
ExecuteInput = Data.define(
|
23
|
+
:proc,
|
24
|
+
:args,
|
25
|
+
:headers
|
26
|
+
)
|
27
|
+
|
28
|
+
# Inbound interceptor for intercepting inbound activity calls. This should be extended by users needing to
|
29
|
+
# intercept activities.
|
30
|
+
class Inbound
|
31
|
+
# @return [Inbound] Next interceptor in the chain.
|
32
|
+
attr_reader :next_interceptor
|
33
|
+
|
34
|
+
# Initialize inbound with the next interceptor in the chain.
|
35
|
+
#
|
36
|
+
# @param next_interceptor [Inbound] Next interceptor in the chain.
|
37
|
+
def initialize(next_interceptor)
|
38
|
+
@next_interceptor = next_interceptor
|
39
|
+
end
|
40
|
+
|
41
|
+
# Initialize the outbound interceptor. This should be extended by users to return their own {Outbound}
|
42
|
+
# implementation that wraps the parameter here.
|
43
|
+
#
|
44
|
+
# @param outbound [Outbound] Next outbound interceptor in the chain.
|
45
|
+
# @return [Outbound] Outbound activity interceptor.
|
46
|
+
def init(outbound)
|
47
|
+
@next_interceptor.init(outbound)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Execute an activity and return result or raise exception. Next interceptor in chain (i.e. `super`) will
|
51
|
+
# perform the execution.
|
52
|
+
#
|
53
|
+
# @param input [ExecuteInput] Input information.
|
54
|
+
# @return [Object] Activity result.
|
55
|
+
def execute(input)
|
56
|
+
@next_interceptor.execute(input)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Input for {Outbound.heartbeat}.
|
61
|
+
HeartbeatInput = Data.define(
|
62
|
+
:details
|
63
|
+
)
|
64
|
+
|
65
|
+
# Outbound interceptor for intercepting outbound activity calls. This should be extended by users needing to
|
66
|
+
# intercept activity calls.
|
67
|
+
class Outbound
|
68
|
+
# @return [Outbound] Next interceptor in the chain.
|
69
|
+
attr_reader :next_interceptor
|
70
|
+
|
71
|
+
# Initialize outbound with the next interceptor in the chain.
|
72
|
+
#
|
73
|
+
# @param next_interceptor [Outbound] Next interceptor in the chain.
|
74
|
+
def initialize(next_interceptor)
|
75
|
+
@next_interceptor = next_interceptor
|
76
|
+
end
|
77
|
+
|
78
|
+
# Issue a heartbeat.
|
79
|
+
#
|
80
|
+
# @param input [HeartbeatInput] Input information.
|
81
|
+
def heartbeat(input)
|
82
|
+
@next_interceptor.heartbeat(input)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Mixin for intercepting workflow worker work. Classes that `include` may implement their own {intercept_workflow}
|
88
|
+
# that returns their own instance of {Inbound}.
|
89
|
+
#
|
90
|
+
# @note Input classes herein may get new required fields added and therefore the constructors of the Input classes
|
91
|
+
# may change in backwards incompatible ways. Users should not try to construct Input classes themselves.
|
92
|
+
module Workflow
|
93
|
+
# Method called when intercepting a workflow. This is called when creating a workflow instance.
|
94
|
+
#
|
95
|
+
# @param next_interceptor [Inbound] Next interceptor in the chain that should be called. This is usually passed
|
96
|
+
# to {Inbound} constructor.
|
97
|
+
# @return [Inbound] Interceptor to be called for workflow calls.
|
98
|
+
def intercept_workflow(next_interceptor)
|
99
|
+
next_interceptor
|
100
|
+
end
|
101
|
+
|
102
|
+
# Input for {Inbound.execute}.
|
103
|
+
ExecuteInput = Data.define(
|
104
|
+
:args,
|
105
|
+
:headers
|
106
|
+
)
|
107
|
+
|
108
|
+
# Input for {Inbound.handle_signal}.
|
109
|
+
HandleSignalInput = Data.define(
|
110
|
+
:signal,
|
111
|
+
:args,
|
112
|
+
:definition,
|
113
|
+
:headers
|
114
|
+
)
|
115
|
+
|
116
|
+
# Input for {Inbound.handle_query}.
|
117
|
+
HandleQueryInput = Data.define(
|
118
|
+
:id,
|
119
|
+
:query,
|
120
|
+
:args,
|
121
|
+
:definition,
|
122
|
+
:headers
|
123
|
+
)
|
124
|
+
|
125
|
+
# Input for {Inbound.validate_update} and {Inbound.handle_update}.
|
126
|
+
HandleUpdateInput = Data.define(
|
127
|
+
:id,
|
128
|
+
:update,
|
129
|
+
:args,
|
130
|
+
:definition,
|
131
|
+
:headers
|
132
|
+
)
|
133
|
+
|
134
|
+
# Inbound interceptor for intercepting inbound workflow calls. This should be extended by users needing to
|
135
|
+
# intercept workflows.
|
136
|
+
class Inbound
|
137
|
+
# @return [Inbound] Next interceptor in the chain.
|
138
|
+
attr_reader :next_interceptor
|
139
|
+
|
140
|
+
# Initialize inbound with the next interceptor in the chain.
|
141
|
+
#
|
142
|
+
# @param next_interceptor [Inbound] Next interceptor in the chain.
|
143
|
+
def initialize(next_interceptor)
|
144
|
+
@next_interceptor = next_interceptor
|
145
|
+
end
|
146
|
+
|
147
|
+
# Initialize the outbound interceptor. This should be extended by users to return their own {Outbound}
|
148
|
+
# implementation that wraps the parameter here.
|
149
|
+
#
|
150
|
+
# @param outbound [Outbound] Next outbound interceptor in the chain.
|
151
|
+
# @return [Outbound] Outbound workflow interceptor.
|
152
|
+
def init(outbound)
|
153
|
+
@next_interceptor.init(outbound)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Execute a workflow and return result or raise exception. Next interceptor in chain (i.e. `super`) will
|
157
|
+
# perform the execution.
|
158
|
+
#
|
159
|
+
# @param input [ExecuteInput] Input information.
|
160
|
+
# @return [Object] Workflow result.
|
161
|
+
def execute(input)
|
162
|
+
@next_interceptor.execute(input)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Handle a workflow signal. Next interceptor in chain (i.e. `super`) will perform the handling.
|
166
|
+
#
|
167
|
+
# @param input [HandleSignalInput] Input information.
|
168
|
+
def handle_signal(input)
|
169
|
+
@next_interceptor.handle_signal(input)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Handle a workflow query and return result or raise exception. Next interceptor in chain (i.e. `super`) will
|
173
|
+
# perform the handling.
|
174
|
+
#
|
175
|
+
# @param input [HandleQueryInput] Input information.
|
176
|
+
# @return [Object] Query result.
|
177
|
+
def handle_query(input)
|
178
|
+
@next_interceptor.handle_query(input)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Validate a workflow update. Next interceptor in chain (i.e. `super`) will perform the validation.
|
182
|
+
#
|
183
|
+
# @param input [HandleUpdateInput] Input information.
|
184
|
+
def validate_update(input)
|
185
|
+
@next_interceptor.validate_update(input)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Handle a workflow update and return result or raise exception. Next interceptor in chain (i.e. `super`) will
|
189
|
+
# perform the handling.
|
190
|
+
#
|
191
|
+
# @param input [HandleUpdateInput] Input information.
|
192
|
+
# @return [Object] Update result.
|
193
|
+
def handle_update(input)
|
194
|
+
@next_interceptor.handle_update(input)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Input for {Outbound.cancel_external_workflow}.
|
199
|
+
CancelExternalWorkflowInput = Data.define(
|
200
|
+
:id,
|
201
|
+
:run_id
|
202
|
+
)
|
203
|
+
|
204
|
+
# Input for {Outbound.execute_activity}.
|
205
|
+
ExecuteActivityInput = Data.define(
|
206
|
+
:activity,
|
207
|
+
:args,
|
208
|
+
:task_queue,
|
209
|
+
:schedule_to_close_timeout,
|
210
|
+
:schedule_to_start_timeout,
|
211
|
+
:start_to_close_timeout,
|
212
|
+
:heartbeat_timeout,
|
213
|
+
:retry_policy,
|
214
|
+
:cancellation,
|
215
|
+
:cancellation_type,
|
216
|
+
:activity_id,
|
217
|
+
:disable_eager_execution,
|
218
|
+
:headers
|
219
|
+
)
|
220
|
+
|
221
|
+
# Input for {Outbound.execute_local_activity}.
|
222
|
+
ExecuteLocalActivityInput = Data.define(
|
223
|
+
:activity,
|
224
|
+
:args,
|
225
|
+
:schedule_to_close_timeout,
|
226
|
+
:schedule_to_start_timeout,
|
227
|
+
:start_to_close_timeout,
|
228
|
+
:retry_policy,
|
229
|
+
:local_retry_threshold,
|
230
|
+
:cancellation,
|
231
|
+
:cancellation_type,
|
232
|
+
:activity_id,
|
233
|
+
:headers
|
234
|
+
)
|
235
|
+
|
236
|
+
# Input for {Outbound.initialize_continue_as_new_error}.
|
237
|
+
InitializeContinueAsNewErrorInput = Data.define(
|
238
|
+
:error
|
239
|
+
)
|
240
|
+
|
241
|
+
# Input for {Outbound.signal_child_workflow}.
|
242
|
+
SignalChildWorkflowInput = Data.define(
|
243
|
+
:id,
|
244
|
+
:signal,
|
245
|
+
:args,
|
246
|
+
:cancellation,
|
247
|
+
:headers
|
248
|
+
)
|
249
|
+
|
250
|
+
# Input for {Outbound.signal_external_workflow}.
|
251
|
+
SignalExternalWorkflowInput = Data.define(
|
252
|
+
:id,
|
253
|
+
:run_id,
|
254
|
+
:signal,
|
255
|
+
:args,
|
256
|
+
:cancellation,
|
257
|
+
:headers
|
258
|
+
)
|
259
|
+
|
260
|
+
# Input for {Outbound.sleep}.
|
261
|
+
SleepInput = Data.define(
|
262
|
+
:duration,
|
263
|
+
:summary,
|
264
|
+
:cancellation
|
265
|
+
)
|
266
|
+
|
267
|
+
# Input for {Outbound.start_child_workflow}.
|
268
|
+
StartChildWorkflowInput = Data.define(
|
269
|
+
:workflow,
|
270
|
+
:args,
|
271
|
+
:id,
|
272
|
+
:task_queue,
|
273
|
+
:cancellation,
|
274
|
+
:cancellation_type,
|
275
|
+
:parent_close_policy,
|
276
|
+
:execution_timeout,
|
277
|
+
:run_timeout,
|
278
|
+
:task_timeout,
|
279
|
+
:id_reuse_policy,
|
280
|
+
:retry_policy,
|
281
|
+
:cron_schedule,
|
282
|
+
:memo,
|
283
|
+
:search_attributes,
|
284
|
+
:headers
|
285
|
+
)
|
286
|
+
|
287
|
+
# Outbound interceptor for intercepting outbound workflow calls. This should be extended by users needing to
|
288
|
+
# intercept workflow calls.
|
289
|
+
class Outbound
|
290
|
+
# @return [Outbound] Next interceptor in the chain.
|
291
|
+
attr_reader :next_interceptor
|
292
|
+
|
293
|
+
# Initialize outbound with the next interceptor in the chain.
|
294
|
+
#
|
295
|
+
# @param next_interceptor [Outbound] Next interceptor in the chain.
|
296
|
+
def initialize(next_interceptor)
|
297
|
+
@next_interceptor = next_interceptor
|
298
|
+
end
|
299
|
+
|
300
|
+
# Cancel external workflow.
|
301
|
+
#
|
302
|
+
# @param input [CancelExternalWorkflowInput] Input.
|
303
|
+
def cancel_external_workflow(input)
|
304
|
+
@next_interceptor.cancel_external_workflow(input)
|
305
|
+
end
|
306
|
+
|
307
|
+
# Execute activity.
|
308
|
+
#
|
309
|
+
# @param input [ExecuteActivityInput] Input.
|
310
|
+
# @return [Object] Activity result.
|
311
|
+
def execute_activity(input)
|
312
|
+
@next_interceptor.execute_activity(input)
|
313
|
+
end
|
314
|
+
|
315
|
+
# Execute local activity.
|
316
|
+
#
|
317
|
+
# @param input [ExecuteLocalActivityInput] Input.
|
318
|
+
# @return [Object] Activity result.
|
319
|
+
def execute_local_activity(input)
|
320
|
+
@next_interceptor.execute_local_activity(input)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Initialize continue as new error.
|
324
|
+
#
|
325
|
+
# @param input [InitializeContinueAsNewErrorInput] Input.
|
326
|
+
def initialize_continue_as_new_error(input)
|
327
|
+
@next_interceptor.initialize_continue_as_new_error(input)
|
328
|
+
end
|
329
|
+
|
330
|
+
# Signal child workflow.
|
331
|
+
#
|
332
|
+
# @param input [SignalChildWorkflowInput] Input.
|
333
|
+
def signal_child_workflow(input)
|
334
|
+
@next_interceptor.signal_child_workflow(input)
|
335
|
+
end
|
336
|
+
|
337
|
+
# Signal external workflow.
|
338
|
+
#
|
339
|
+
# @param input [SignalExternalWorkflowInput] Input.
|
340
|
+
def signal_external_workflow(input)
|
341
|
+
@next_interceptor.signal_external_workflow(input)
|
342
|
+
end
|
343
|
+
|
344
|
+
# Sleep.
|
345
|
+
#
|
346
|
+
# @param input [SleepInput] Input.
|
347
|
+
def sleep(input)
|
348
|
+
@next_interceptor.sleep(input)
|
349
|
+
end
|
350
|
+
|
351
|
+
# Start child workflow.
|
352
|
+
#
|
353
|
+
# @param input [StartChildWorkflowInput] Input.
|
354
|
+
# @return [Workflow::ChildWorkflowHandle] Child workflow handle.
|
355
|
+
def start_child_workflow(input)
|
356
|
+
@next_interceptor.start_child_workflow(input)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Much of this logic taken from
|
4
|
+
# https://github.com/ruby-concurrency/concurrent-ruby/blob/044020f44b36930b863b930f3ee8fa1e9f750469/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb,
|
5
|
+
# see MIT license at
|
6
|
+
# https://github.com/ruby-concurrency/concurrent-ruby/blob/044020f44b36930b863b930f3ee8fa1e9f750469/LICENSE.txt
|
7
|
+
|
8
|
+
module Temporalio
|
9
|
+
class Worker
|
10
|
+
# Implementation of a thread pool. This implementation is a stripped down form of Concurrent Ruby's
|
11
|
+
# `CachedThreadPool`.
|
12
|
+
class ThreadPool
|
13
|
+
# @return [ThreadPool] Default/shared thread pool instance with unlimited max threads.
|
14
|
+
def self.default
|
15
|
+
@default ||= new
|
16
|
+
end
|
17
|
+
|
18
|
+
# @!visibility private
|
19
|
+
def self._monotonic_time
|
20
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Create a new thread pool that creates threads as needed.
|
24
|
+
#
|
25
|
+
# @param max_threads [Integer, nil] Maximum number of thread workers to create, or nil for unlimited max.
|
26
|
+
# @param idle_timeout [Float] Number of seconds before a thread worker with no work should be stopped. Note,
|
27
|
+
# the check of whether a thread worker is idle is only done on each new {execute} call.
|
28
|
+
def initialize(max_threads: nil, idle_timeout: 20)
|
29
|
+
@max_threads = max_threads
|
30
|
+
@idle_timeout = idle_timeout
|
31
|
+
|
32
|
+
@mutex = Mutex.new
|
33
|
+
@pool = []
|
34
|
+
@ready = []
|
35
|
+
@queue = []
|
36
|
+
@scheduled_task_count = 0
|
37
|
+
@completed_task_count = 0
|
38
|
+
@largest_length = 0
|
39
|
+
@workers_counter = 0
|
40
|
+
@prune_interval = @idle_timeout / 2
|
41
|
+
@next_prune_time = ThreadPool._monotonic_time + @prune_interval
|
42
|
+
end
|
43
|
+
|
44
|
+
# Execute the given block in a thread. The block should be built to never raise and need no arguments.
|
45
|
+
#
|
46
|
+
# @yield Block to execute.
|
47
|
+
def execute(&block)
|
48
|
+
@mutex.synchronize do
|
49
|
+
locked_assign_worker(&block) || locked_enqueue(&block)
|
50
|
+
@scheduled_task_count += 1
|
51
|
+
locked_prune_pool if @next_prune_time < ThreadPool._monotonic_time
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Integer] The largest number of threads that have been created in the pool since construction.
|
56
|
+
def largest_length
|
57
|
+
@mutex.synchronize { @largest_length }
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Integer] The number of tasks that have been scheduled for execution on the pool since construction.
|
61
|
+
def scheduled_task_count
|
62
|
+
@mutex.synchronize { @scheduled_task_count }
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Integer] The number of tasks that have been completed by the pool since construction.
|
66
|
+
def completed_task_count
|
67
|
+
@mutex.synchronize { @completed_task_count }
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Integer] The number of threads that are actively executing tasks.
|
71
|
+
def active_count
|
72
|
+
@mutex.synchronize { @pool.length - @ready.length }
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Integer] The number of threads currently in the pool.
|
76
|
+
def length
|
77
|
+
@mutex.synchronize { @pool.length }
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Integer] The number of tasks in the queue awaiting execution.
|
81
|
+
def queue_length
|
82
|
+
@mutex.synchronize { @queue.length }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Gracefully shutdown each thread when it is done with its current task. This should not be called until all
|
86
|
+
# workers using this executor are complete. This does not need to be called at all on program exit (e.g. for the
|
87
|
+
# global default).
|
88
|
+
def shutdown
|
89
|
+
@mutex.synchronize do
|
90
|
+
# Stop all workers
|
91
|
+
@pool.each(&:stop)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Kill each thread. This should not be called until all workers using this executor are complete. This does not
|
96
|
+
# need to be called at all on program exit (e.g. for the global default).
|
97
|
+
def kill
|
98
|
+
@mutex.synchronize do
|
99
|
+
# Kill all workers
|
100
|
+
@pool.each(&:kill)
|
101
|
+
@pool.clear
|
102
|
+
@ready.clear
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# @!visibility private
|
107
|
+
def _remove_busy_worker(worker)
|
108
|
+
@mutex.synchronize { locked_remove_busy_worker(worker) }
|
109
|
+
end
|
110
|
+
|
111
|
+
# @!visibility private
|
112
|
+
def _ready_worker(worker, last_message)
|
113
|
+
@mutex.synchronize { locked_ready_worker(worker, last_message) }
|
114
|
+
end
|
115
|
+
|
116
|
+
# @!visibility private
|
117
|
+
def _worker_died(worker)
|
118
|
+
@mutex.synchronize { locked_worker_died(worker) }
|
119
|
+
end
|
120
|
+
|
121
|
+
# @!visibility private
|
122
|
+
def _worker_task_completed
|
123
|
+
@mutex.synchronize { @completed_task_count += 1 }
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def locked_assign_worker(&block)
|
129
|
+
# keep growing if the pool is not at the minimum yet
|
130
|
+
worker, = @ready.pop || locked_add_busy_worker
|
131
|
+
if worker
|
132
|
+
worker << block
|
133
|
+
true
|
134
|
+
else
|
135
|
+
false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def locked_enqueue(&block)
|
140
|
+
@queue << block
|
141
|
+
end
|
142
|
+
|
143
|
+
def locked_add_busy_worker
|
144
|
+
return if @max_threads && @pool.size >= @max_threads
|
145
|
+
|
146
|
+
@workers_counter += 1
|
147
|
+
@pool << (worker = Worker.new(self, @workers_counter))
|
148
|
+
@largest_length = @pool.length if @pool.length > @largest_length
|
149
|
+
worker
|
150
|
+
end
|
151
|
+
|
152
|
+
def locked_prune_pool
|
153
|
+
now = ThreadPool._monotonic_time
|
154
|
+
stopped_workers = 0
|
155
|
+
while !@ready.empty? && (@pool.size - stopped_workers).positive?
|
156
|
+
worker, last_message = @ready.first
|
157
|
+
break unless now - last_message > @idle_timeout
|
158
|
+
|
159
|
+
stopped_workers += 1
|
160
|
+
@ready.shift
|
161
|
+
worker << :stop
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
@next_prune_time = ThreadPool._monotonic_time + @prune_interval
|
166
|
+
end
|
167
|
+
|
168
|
+
def locked_remove_busy_worker(worker)
|
169
|
+
@pool.delete(worker)
|
170
|
+
end
|
171
|
+
|
172
|
+
def locked_ready_worker(worker, last_message)
|
173
|
+
block = @queue.shift
|
174
|
+
if block
|
175
|
+
worker << block
|
176
|
+
else
|
177
|
+
@ready.push([worker, last_message])
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def locked_worker_died(worker)
|
182
|
+
locked_remove_busy_worker(worker)
|
183
|
+
replacement_worker = locked_add_busy_worker
|
184
|
+
locked_ready_worker(replacement_worker, ThreadPool._monotonic_time) if replacement_worker
|
185
|
+
end
|
186
|
+
|
187
|
+
# @!visibility private
|
188
|
+
class Worker
|
189
|
+
def initialize(pool, id)
|
190
|
+
@queue = Queue.new
|
191
|
+
@thread = Thread.new(@queue, pool) do |my_queue, my_pool|
|
192
|
+
catch(:stop) do
|
193
|
+
loop do
|
194
|
+
case block = my_queue.pop
|
195
|
+
when :stop
|
196
|
+
pool._remove_busy_worker(self)
|
197
|
+
throw :stop
|
198
|
+
else
|
199
|
+
begin
|
200
|
+
block.call
|
201
|
+
my_pool._worker_task_completed
|
202
|
+
my_pool._ready_worker(self, ThreadPool._monotonic_time)
|
203
|
+
rescue StandardError => e
|
204
|
+
# Ignore
|
205
|
+
warn("Unexpected execute block error: #{e.full_message}")
|
206
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
207
|
+
warn("Unexpected execute block exception: #{e.full_message}")
|
208
|
+
my_pool._worker_died(self)
|
209
|
+
throw :stop
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
@thread.name = "temporal-thread-#{id}"
|
216
|
+
end
|
217
|
+
|
218
|
+
# @!visibility private
|
219
|
+
def <<(block)
|
220
|
+
@queue << block
|
221
|
+
end
|
222
|
+
|
223
|
+
# @!visibility private
|
224
|
+
def stop
|
225
|
+
@queue << :stop
|
226
|
+
end
|
227
|
+
|
228
|
+
# @!visibility private
|
229
|
+
def kill
|
230
|
+
@thread.kill
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
private_constant :Worker
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|