temporalio 0.3.0-x86_64-linux-musl → 0.5.0-x86_64-linux-musl

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.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/Gemfile +4 -0
  4. data/Rakefile +1 -1
  5. data/lib/temporalio/activity/cancellation_details.rb +58 -0
  6. data/lib/temporalio/activity/context.rb +17 -1
  7. data/lib/temporalio/activity/definition.rb +45 -4
  8. data/lib/temporalio/activity/info.rb +28 -4
  9. data/lib/temporalio/activity.rb +2 -0
  10. data/lib/temporalio/api/activity/v1/message.rb +1 -1
  11. data/lib/temporalio/api/batch/v1/message.rb +9 -2
  12. data/lib/temporalio/api/cloud/account/v1/message.rb +1 -1
  13. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +11 -2
  14. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +2 -2
  15. data/lib/temporalio/api/cloud/identity/v1/message.rb +7 -2
  16. data/lib/temporalio/api/cloud/namespace/v1/message.rb +6 -2
  17. data/lib/temporalio/api/cloud/nexus/v1/message.rb +3 -2
  18. data/lib/temporalio/api/cloud/operation/v1/message.rb +1 -1
  19. data/lib/temporalio/api/cloud/region/v1/message.rb +1 -1
  20. data/lib/temporalio/api/cloud/resource/v1/message.rb +1 -1
  21. data/lib/temporalio/api/cloud/sink/v1/message.rb +1 -1
  22. data/lib/temporalio/api/cloud/usage/v1/message.rb +1 -1
  23. data/lib/temporalio/api/command/v1/message.rb +2 -2
  24. data/lib/temporalio/api/common/v1/grpc_status.rb +1 -1
  25. data/lib/temporalio/api/common/v1/message.rb +4 -2
  26. data/lib/temporalio/api/deployment/v1/message.rb +39 -0
  27. data/lib/temporalio/api/enums/v1/batch_operation.rb +2 -2
  28. data/lib/temporalio/api/enums/v1/command_type.rb +1 -1
  29. data/lib/temporalio/api/enums/v1/common.rb +5 -2
  30. data/lib/temporalio/api/enums/v1/deployment.rb +24 -0
  31. data/lib/temporalio/api/enums/v1/event_type.rb +2 -2
  32. data/lib/temporalio/api/enums/v1/failed_cause.rb +2 -2
  33. data/lib/temporalio/api/enums/v1/namespace.rb +1 -1
  34. data/lib/temporalio/api/enums/v1/nexus.rb +21 -0
  35. data/lib/temporalio/api/enums/v1/query.rb +1 -1
  36. data/lib/temporalio/api/enums/v1/reset.rb +2 -2
  37. data/lib/temporalio/api/enums/v1/schedule.rb +1 -1
  38. data/lib/temporalio/api/enums/v1/task_queue.rb +1 -1
  39. data/lib/temporalio/api/enums/v1/update.rb +1 -1
  40. data/lib/temporalio/api/enums/v1/workflow.rb +3 -2
  41. data/lib/temporalio/api/errordetails/v1/message.rb +4 -2
  42. data/lib/temporalio/api/export/v1/message.rb +1 -1
  43. data/lib/temporalio/api/failure/v1/message.rb +5 -2
  44. data/lib/temporalio/api/filter/v1/message.rb +1 -1
  45. data/lib/temporalio/api/history/v1/message.rb +6 -2
  46. data/lib/temporalio/api/namespace/v1/message.rb +1 -1
  47. data/lib/temporalio/api/nexus/v1/message.rb +3 -2
  48. data/lib/temporalio/api/operatorservice/v1/request_response.rb +1 -1
  49. data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
  50. data/lib/temporalio/api/payload_visitor.rb +162 -7
  51. data/lib/temporalio/api/protocol/v1/message.rb +1 -1
  52. data/lib/temporalio/api/query/v1/message.rb +3 -2
  53. data/lib/temporalio/api/replication/v1/message.rb +1 -1
  54. data/lib/temporalio/api/rules/v1/message.rb +27 -0
  55. data/lib/temporalio/api/schedule/v1/message.rb +2 -2
  56. data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +1 -1
  57. data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +1 -1
  58. data/lib/temporalio/api/sdk/v1/user_metadata.rb +1 -1
  59. data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +1 -1
  60. data/lib/temporalio/api/taskqueue/v1/message.rb +5 -2
  61. data/lib/temporalio/api/testservice/v1/request_response.rb +1 -1
  62. data/lib/temporalio/api/testservice/v1/service.rb +1 -1
  63. data/lib/temporalio/api/update/v1/message.rb +1 -1
  64. data/lib/temporalio/api/version/v1/message.rb +1 -1
  65. data/lib/temporalio/api/worker/v1/message.rb +30 -0
  66. data/lib/temporalio/api/workflow/v1/message.rb +22 -2
  67. data/lib/temporalio/api/workflowservice/v1/request_response.rb +58 -12
  68. data/lib/temporalio/api/workflowservice/v1/service.rb +2 -2
  69. data/lib/temporalio/api.rb +1 -0
  70. data/lib/temporalio/client/async_activity_handle.rb +12 -4
  71. data/lib/temporalio/client/connection/cloud_service.rb +60 -0
  72. data/lib/temporalio/client/connection/workflow_service.rb +343 -28
  73. data/lib/temporalio/client/interceptor.rb +64 -7
  74. data/lib/temporalio/client/schedule.rb +35 -3
  75. data/lib/temporalio/client/with_start_workflow_operation.rb +123 -0
  76. data/lib/temporalio/client/workflow_execution.rb +19 -0
  77. data/lib/temporalio/client/workflow_handle.rb +47 -7
  78. data/lib/temporalio/client/workflow_update_handle.rb +9 -3
  79. data/lib/temporalio/client.rb +231 -4
  80. data/lib/temporalio/common_enums.rb +14 -0
  81. data/lib/temporalio/contrib/open_telemetry.rb +474 -0
  82. data/lib/temporalio/converters/data_converter.rb +18 -8
  83. data/lib/temporalio/converters/failure_converter.rb +6 -3
  84. data/lib/temporalio/converters/payload_converter/binary_null.rb +2 -2
  85. data/lib/temporalio/converters/payload_converter/binary_plain.rb +2 -2
  86. data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +2 -2
  87. data/lib/temporalio/converters/payload_converter/composite.rb +6 -4
  88. data/lib/temporalio/converters/payload_converter/encoding.rb +4 -2
  89. data/lib/temporalio/converters/payload_converter/json_plain.rb +2 -2
  90. data/lib/temporalio/converters/payload_converter/json_protobuf.rb +2 -2
  91. data/lib/temporalio/converters/payload_converter.rb +16 -6
  92. data/lib/temporalio/error/failure.rb +19 -1
  93. data/lib/temporalio/error.rb +2 -1
  94. data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.so +0 -0
  95. data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
  96. data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
  97. data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +1 -1
  98. data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +3 -2
  99. data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +1 -1
  100. data/lib/temporalio/internal/bridge/api/common/common.rb +3 -2
  101. data/lib/temporalio/internal/bridge/api/core_interface.rb +1 -1
  102. data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +1 -1
  103. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +3 -2
  104. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +2 -2
  105. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +3 -2
  106. data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +3 -2
  107. data/lib/temporalio/internal/bridge/runtime.rb +3 -0
  108. data/lib/temporalio/internal/bridge/testing.rb +3 -0
  109. data/lib/temporalio/internal/bridge/worker.rb +28 -4
  110. data/lib/temporalio/internal/bridge.rb +1 -1
  111. data/lib/temporalio/internal/client/implementation.rb +281 -51
  112. data/lib/temporalio/internal/proto_utils.rb +38 -6
  113. data/lib/temporalio/internal/worker/activity_worker.rb +107 -25
  114. data/lib/temporalio/internal/worker/multi_runner.rb +2 -2
  115. data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +8 -6
  116. data/lib/temporalio/internal/worker/workflow_instance/context.rb +96 -5
  117. data/lib/temporalio/internal/worker/workflow_instance/details.rb +7 -2
  118. data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +2 -2
  119. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +64 -18
  120. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +39 -40
  121. data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +22 -2
  122. data/lib/temporalio/internal/worker/workflow_instance.rb +134 -55
  123. data/lib/temporalio/internal/worker/workflow_worker.rb +19 -6
  124. data/lib/temporalio/priority.rb +59 -0
  125. data/lib/temporalio/runtime/metric_buffer.rb +94 -0
  126. data/lib/temporalio/runtime.rb +48 -10
  127. data/lib/temporalio/search_attributes.rb +13 -0
  128. data/lib/temporalio/testing/activity_environment.rb +49 -10
  129. data/lib/temporalio/testing/workflow_environment.rb +29 -6
  130. data/lib/temporalio/version.rb +1 -1
  131. data/lib/temporalio/versioning_override.rb +56 -0
  132. data/lib/temporalio/worker/deployment_options.rb +45 -0
  133. data/lib/temporalio/worker/illegal_workflow_call_validator.rb +64 -0
  134. data/lib/temporalio/worker/interceptor.rb +16 -1
  135. data/lib/temporalio/worker/poller_behavior.rb +61 -0
  136. data/lib/temporalio/worker/thread_pool.rb +6 -6
  137. data/lib/temporalio/worker/workflow_executor/thread_pool.rb +9 -3
  138. data/lib/temporalio/worker/workflow_replayer.rb +19 -13
  139. data/lib/temporalio/worker.rb +97 -27
  140. data/lib/temporalio/worker_deployment_version.rb +67 -0
  141. data/lib/temporalio/workflow/child_workflow_handle.rb +10 -2
  142. data/lib/temporalio/workflow/definition.rb +217 -35
  143. data/lib/temporalio/workflow/external_workflow_handle.rb +3 -1
  144. data/lib/temporalio/workflow/future.rb +2 -2
  145. data/lib/temporalio/workflow/info.rb +26 -1
  146. data/lib/temporalio/workflow.rb +113 -15
  147. data/lib/temporalio.rb +1 -0
  148. data/temporalio.gemspec +3 -1
  149. metadata +33 -4
@@ -22,6 +22,7 @@ module Temporalio
22
22
  ExecuteInput = Data.define(
23
23
  :proc,
24
24
  :args,
25
+ :result_hint,
25
26
  :headers
26
27
  )
27
28
 
@@ -59,7 +60,8 @@ module Temporalio
59
60
 
60
61
  # Input for {Outbound.heartbeat}.
61
62
  HeartbeatInput = Data.define(
62
- :details
63
+ :details,
64
+ :detail_hints
63
65
  )
64
66
 
65
67
  # Outbound interceptor for intercepting outbound activity calls. This should be extended by users needing to
@@ -206,6 +208,7 @@ module Temporalio
206
208
  :activity,
207
209
  :args,
208
210
  :task_queue,
211
+ :summary,
209
212
  :schedule_to_close_timeout,
210
213
  :schedule_to_start_timeout,
211
214
  :start_to_close_timeout,
@@ -215,6 +218,9 @@ module Temporalio
215
218
  :cancellation_type,
216
219
  :activity_id,
217
220
  :disable_eager_execution,
221
+ :priority,
222
+ :arg_hints,
223
+ :result_hint,
218
224
  :headers
219
225
  )
220
226
 
@@ -230,6 +236,8 @@ module Temporalio
230
236
  :cancellation,
231
237
  :cancellation_type,
232
238
  :activity_id,
239
+ :arg_hints,
240
+ :result_hint,
233
241
  :headers
234
242
  )
235
243
 
@@ -244,6 +252,7 @@ module Temporalio
244
252
  :signal,
245
253
  :args,
246
254
  :cancellation,
255
+ :arg_hints,
247
256
  :headers
248
257
  )
249
258
 
@@ -254,6 +263,7 @@ module Temporalio
254
263
  :signal,
255
264
  :args,
256
265
  :cancellation,
266
+ :arg_hints,
257
267
  :headers
258
268
  )
259
269
 
@@ -270,6 +280,8 @@ module Temporalio
270
280
  :args,
271
281
  :id,
272
282
  :task_queue,
283
+ :static_summary,
284
+ :static_details,
273
285
  :cancellation,
274
286
  :cancellation_type,
275
287
  :parent_close_policy,
@@ -281,6 +293,9 @@ module Temporalio
281
293
  :cron_schedule,
282
294
  :memo,
283
295
  :search_attributes,
296
+ :priority,
297
+ :arg_hints,
298
+ :result_hint,
284
299
  :headers
285
300
  )
286
301
 
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Temporalio
4
+ class Worker
5
+ # Base class for poller behaviors that control how polling scales.
6
+ class PollerBehavior
7
+ # @!visibility private
8
+ def _to_bridge_options
9
+ raise NotImplementedError, 'Subclasses must implement this method'
10
+ end
11
+
12
+ # A poller behavior that attempts to poll as long as a slot is available, up to the
13
+ # provided maximum. Cannot be less than two for workflow tasks, or one for other tasks.
14
+ class SimpleMaximum < PollerBehavior
15
+ # @return [Integer] Maximum number of concurrent poll requests.
16
+ attr_reader :maximum
17
+
18
+ # @param maximum [Integer] Maximum number of concurrent poll requests.
19
+ def initialize(maximum)
20
+ super()
21
+ @maximum = maximum
22
+ end
23
+
24
+ # @!visibility private
25
+ def _to_bridge_options
26
+ Internal::Bridge::Worker::PollerBehaviorSimpleMaximum.new(simple_maximum: @maximum)
27
+ end
28
+ end
29
+
30
+ # A poller behavior that automatically scales the number of pollers based on feedback
31
+ # from the server. A slot must be available before beginning polling.
32
+ class Autoscaling < PollerBehavior
33
+ # @return [Integer] Minimum number of poll calls (assuming slots are available).
34
+ attr_reader :minimum
35
+ # @return [Integer] Maximum number of poll calls that will ever be open at once.
36
+ attr_reader :maximum
37
+ # @return [Integer] Number of polls attempted initially before scaling kicks in.
38
+ attr_reader :initial
39
+
40
+ # @param minimum [Integer] Minimum number of poll calls (assuming slots are available).
41
+ # @param maximum [Integer] Maximum number of poll calls that will ever be open at once.
42
+ # @param initial [Integer] Number of polls attempted initially before scaling kicks in.
43
+ def initialize(minimum: 1, maximum: 100, initial: 5)
44
+ super()
45
+ @minimum = minimum
46
+ @maximum = maximum
47
+ @initial = initial
48
+ end
49
+
50
+ # @!visibility private
51
+ def _to_bridge_options
52
+ Internal::Bridge::Worker::PollerBehaviorAutoscaling.new(
53
+ minimum: @minimum,
54
+ maximum: @maximum,
55
+ initial: @initial
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
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
3
  module Temporalio
9
4
  class Worker
10
5
  # Implementation of a thread pool. This implementation is a stripped down form of Concurrent Ruby's
11
6
  # `CachedThreadPool`.
12
7
  class ThreadPool
8
+ # Much of this logic taken from
9
+ # https://github.com/ruby-concurrency/concurrent-ruby/blob/044020f44b36930b863b930f3ee8fa1e9f750469/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb,
10
+ # see MIT license at
11
+ # https://github.com/ruby-concurrency/concurrent-ruby/blob/044020f44b36930b863b930f3ee8fa1e9f750469/LICENSE.txt
12
+
13
13
  # @return [ThreadPool] Default/shared thread pool instance with unlimited max threads.
14
14
  def self.default
15
15
  @default ||= new
@@ -125,7 +125,7 @@ module Temporalio
125
125
 
126
126
  private
127
127
 
128
- def locked_assign_worker(&block)
128
+ def locked_assign_worker(&block) # rubocop:disable Naming/PredicateMethod
129
129
  # keep growing if the pool is not at the minimum yet
130
130
  worker, = @ready.pop || locked_add_busy_worker
131
131
  if worker
@@ -186,8 +186,12 @@ module Temporalio
186
186
  raise 'Missing initialize job in initial activation' unless init_job
187
187
 
188
188
  # Obtain definition
189
- definition = worker_state.workflow_definitions[init_job.workflow_type] ||
190
- worker_state.workflow_definitions[nil]
189
+ definition = worker_state.workflow_definitions[init_job.workflow_type]
190
+ # If not present and not reserved, try dynamic
191
+ if !definition && !Internal::ProtoUtils.reserved_name?(init_job.workflow_type)
192
+ definition = worker_state.workflow_definitions[nil]
193
+ end
194
+
191
195
  unless definition
192
196
  raise Error::ApplicationError.new(
193
197
  "Workflow type #{init_job.workflow_type} is not registered on this worker, available workflows: " +
@@ -209,7 +213,9 @@ module Temporalio
209
213
  interceptors: worker_state.workflow_interceptors,
210
214
  disable_eager_activity_execution: worker_state.disable_eager_activity_execution,
211
215
  illegal_calls: worker_state.illegal_calls,
212
- workflow_failure_exception_types: worker_state.workflow_failure_exception_types
216
+ workflow_failure_exception_types: worker_state.workflow_failure_exception_types,
217
+ unsafe_workflow_io_enabled: worker_state.unsafe_workflow_io_enabled,
218
+ assert_valid_local_activity: worker_state.assert_valid_local_activity
213
219
  )
214
220
  )
215
221
  end
@@ -7,6 +7,7 @@ require 'temporalio/internal/bridge/worker'
7
7
  require 'temporalio/internal/worker/multi_runner'
8
8
  require 'temporalio/internal/worker/workflow_worker'
9
9
  require 'temporalio/worker/interceptor'
10
+ require 'temporalio/worker/poller_behavior'
10
11
  require 'temporalio/worker/thread_pool'
11
12
  require 'temporalio/worker/tuner'
12
13
  require 'temporalio/worker/workflow_executor'
@@ -24,12 +25,12 @@ module Temporalio
24
25
  :data_converter,
25
26
  :workflow_executor,
26
27
  :interceptors,
27
- :build_id,
28
28
  :identity,
29
29
  :logger,
30
30
  :illegal_workflow_calls,
31
31
  :workflow_failure_exception_types,
32
32
  :workflow_payload_codec_thread_pool,
33
+ :unsafe_workflow_io_enabled,
33
34
  :debug_mode,
34
35
  :runtime
35
36
  )
@@ -50,9 +51,6 @@ module Temporalio
50
51
  # @param workflow_executor [WorkflowExecutor] Workflow executor that workflow tasks run within. This must be a
51
52
  # {WorkflowExecutor::ThreadPool} currently.
52
53
  # @param interceptors [Array<Interceptor::Workflow>] Workflow interceptors.
53
- # @param build_id [String] Unique identifier for the current runtime. This is best set as a unique value
54
- # representing all code and should change only when code does. This can be something like a git commit hash. If
55
- # unset, default is hash of known Ruby code.
56
54
  # @param identity [String, nil] Override the identity for this replater.
57
55
  # @param logger [Logger] Logger to use. Defaults to stdout with warn level. Callers setting this logger are
58
56
  # responsible for closing it.
@@ -69,6 +67,9 @@ module Temporalio
69
67
  # @param workflow_payload_codec_thread_pool [ThreadPool, nil] Thread pool to run payload codec encode/decode
70
68
  # within. This is required if a payload codec exists and the worker is not fiber based. Codecs can potentially
71
69
  # block execution which is why they need to be run in the background.
70
+ # @param unsafe_workflow_io_enabled [Boolean] If false, the default, workflow code that invokes io_wait on the
71
+ # fiber scheduler will fail. Instead of setting this to true, users are encouraged to use
72
+ # {Workflow::Unsafe.io_enabled} with a block for narrower enabling of IO.
72
73
  # @param debug_mode [Boolean] If true, deadlock detection is disabled. Deadlock detection will fail workflow tasks
73
74
  # if they block the thread for too long. This defaults to true if the `TEMPORAL_DEBUG` environment variable is
74
75
  # `true` or `1`.
@@ -83,12 +84,12 @@ module Temporalio
83
84
  data_converter: Converters::DataConverter.default,
84
85
  workflow_executor: WorkflowExecutor::ThreadPool.default,
85
86
  interceptors: [],
86
- build_id: Worker.default_build_id,
87
87
  identity: nil,
88
88
  logger: Logger.new($stdout, level: Logger::WARN),
89
89
  illegal_workflow_calls: Worker.default_illegal_workflow_calls,
90
90
  workflow_failure_exception_types: [],
91
91
  workflow_payload_codec_thread_pool: nil,
92
+ unsafe_workflow_io_enabled: false,
92
93
  debug_mode: %w[true 1].include?(ENV['TEMPORAL_DEBUG'].to_s.downcase),
93
94
  runtime: Runtime.default,
94
95
  &
@@ -100,17 +101,19 @@ module Temporalio
100
101
  data_converter:,
101
102
  workflow_executor:,
102
103
  interceptors:,
103
- build_id:,
104
104
  identity:,
105
105
  logger:,
106
106
  illegal_workflow_calls:,
107
107
  workflow_failure_exception_types:,
108
108
  workflow_payload_codec_thread_pool:,
109
+ unsafe_workflow_io_enabled:,
109
110
  debug_mode:,
110
111
  runtime:
111
112
  ).freeze
112
113
  # Preload definitions and other settings
113
- @workflow_definitions = Internal::Worker::WorkflowWorker.workflow_definitions(workflows)
114
+ @workflow_definitions = Internal::Worker::WorkflowWorker.workflow_definitions(
115
+ workflows, should_enforce_versioning_behavior: false
116
+ )
114
117
  @nondeterminism_as_workflow_fail, @nondeterminism_as_workflow_fail_for_types =
115
118
  Internal::Worker::WorkflowWorker.bridge_workflow_failure_exception_type_options(
116
119
  workflow_failure_exception_types:, workflow_definitions: @workflow_definitions
@@ -201,12 +204,13 @@ module Temporalio
201
204
  tuner: Tuner.create_fixed(
202
205
  workflow_slots: 2, activity_slots: 1, local_activity_slots: 1
203
206
  )._to_bridge_options,
204
- build_id: options.build_id,
205
207
  identity_override: options.identity,
206
208
  max_cached_workflows: 2,
207
- max_concurrent_workflow_task_polls: 1,
209
+ workflow_task_poller_behavior:
210
+ Temporalio::Worker::PollerBehavior::SimpleMaximum.new(2)._to_bridge_options,
208
211
  nonsticky_to_sticky_poll_ratio: 1.0,
209
- max_concurrent_activity_task_polls: 1,
212
+ activity_task_poller_behavior:
213
+ Temporalio::Worker::PollerBehavior::SimpleMaximum.new(1)._to_bridge_options,
210
214
  no_remote_activities: true,
211
215
  sticky_queue_schedule_to_start_timeout: 1.0,
212
216
  max_heartbeat_throttle_interval: 1.0,
@@ -214,9 +218,9 @@ module Temporalio
214
218
  max_worker_activities_per_second: nil,
215
219
  max_task_queue_activities_per_second: nil,
216
220
  graceful_shutdown_period: 0.0,
217
- use_worker_versioning: false,
218
221
  nondeterminism_as_workflow_fail:,
219
- nondeterminism_as_workflow_fail_for_types:
222
+ nondeterminism_as_workflow_fail_for_types:,
223
+ deployment_options: Worker.default_deployment_options._to_bridge_options
220
224
  )
221
225
  )
222
226
 
@@ -237,8 +241,10 @@ module Temporalio
237
241
  illegal_workflow_calls: options.illegal_workflow_calls,
238
242
  workflow_failure_exception_types: options.workflow_failure_exception_types,
239
243
  workflow_payload_codec_thread_pool: options.workflow_payload_codec_thread_pool,
244
+ unsafe_workflow_io_enabled: options.unsafe_workflow_io_enabled,
240
245
  debug_mode: options.debug_mode,
241
- on_eviction: proc { |_, remove_job| @last_workflow_remove_job = remove_job } # steep:ignore
246
+ on_eviction: proc { |_, remove_job| @last_workflow_remove_job = remove_job }, # steep:ignore
247
+ assert_valid_local_activity: ->(_) {}
242
248
  )
243
249
 
244
250
  # Create the runner
@@ -6,12 +6,16 @@ require 'temporalio/client'
6
6
  require 'temporalio/error'
7
7
  require 'temporalio/internal/bridge'
8
8
  require 'temporalio/internal/bridge/worker'
9
+ require 'temporalio/internal/proto_utils'
9
10
  require 'temporalio/internal/worker/activity_worker'
10
11
  require 'temporalio/internal/worker/multi_runner'
11
12
  require 'temporalio/internal/worker/workflow_instance'
12
13
  require 'temporalio/internal/worker/workflow_worker'
13
14
  require 'temporalio/worker/activity_executor'
15
+ require 'temporalio/worker/deployment_options'
16
+ require 'temporalio/worker/illegal_workflow_call_validator'
14
17
  require 'temporalio/worker/interceptor'
18
+ require 'temporalio/worker/poller_behavior'
15
19
  require 'temporalio/worker/thread_pool'
16
20
  require 'temporalio/worker/tuner'
17
21
  require 'temporalio/worker/workflow_executor'
@@ -32,7 +36,6 @@ module Temporalio
32
36
  :activity_executors,
33
37
  :workflow_executor,
34
38
  :interceptors,
35
- :build_id,
36
39
  :identity,
37
40
  :logger,
38
41
  :max_cached_workflows,
@@ -46,15 +49,20 @@ module Temporalio
46
49
  :max_activities_per_second,
47
50
  :max_task_queue_activities_per_second,
48
51
  :graceful_shutdown_period,
49
- :use_worker_versioning,
50
52
  :disable_eager_activity_execution,
51
53
  :illegal_workflow_calls,
52
54
  :workflow_failure_exception_types,
53
55
  :workflow_payload_codec_thread_pool,
56
+ :unsafe_workflow_io_enabled,
57
+ :deployment_options,
58
+ :workflow_task_poller_behavior,
59
+ :activity_task_poller_behavior,
54
60
  :debug_mode
55
61
  )
56
62
 
57
63
  # Options as returned from {options} for `**to_h` splat use in {initialize}. See {initialize} for details.
64
+ #
65
+ # Note, the `client` within can be replaced via client setter.
58
66
  class Options; end # rubocop:disable Lint/EmptyClass
59
67
 
60
68
  # @return [String] Memoized default build ID. This default value is built as a checksum of all of the loaded Ruby
@@ -85,6 +93,14 @@ module Temporalio
85
93
  build_id
86
94
  end
87
95
 
96
+ # @return [DeploymentOptions] Default deployment options, which does not use worker versioning
97
+ # or a deployment name, and sets the build id to the one from {self.default_build_id}.
98
+ def self.default_deployment_options
99
+ @default_deployment_options ||= DeploymentOptions.new(
100
+ version: WorkerDeploymentVersion.new(deployment_name: '', build_id: Worker.default_build_id)
101
+ )
102
+ end
103
+
88
104
  # Run all workers until cancellation or optional block completes. When the cancellation or block is complete, the
89
105
  # workers are shut down. This will return the block result if everything successful or raise an error if not. See
90
106
  # {run} for details on how worker shutdown works.
@@ -228,8 +244,9 @@ module Temporalio
228
244
  end
229
245
  end
230
246
 
231
- # @return [Hash<String, [:all, Array<Symbol>]>] Default, immutable set illegal calls used for the
232
- # `illegal_workflow_calls` worker option. See the documentation of that option for more details.
247
+ # @return [Hash<String, [:all, Array<Symbol, IllegalWorkflowCallValidator>, IllegalWorkflowCallValidator]>] Default,
248
+ # immutable set illegal calls used for the `illegal_workflow_calls` worker option. See the documentation of that
249
+ # option for more details.
233
250
  def self.default_illegal_workflow_calls
234
251
  @default_illegal_workflow_calls ||= begin
235
252
  hash = {
@@ -268,7 +285,7 @@ module Temporalio
268
285
  'Thread' => %i[abort_on_exception= exit fork handle_interrupt ignore_deadlock= kill new pass
269
286
  pending_interrupt? report_on_exception= start stop initialize join name= priority= raise run
270
287
  terminate thread_variable_set wakeup],
271
- 'Time' => %i[initialize now]
288
+ 'Time' => IllegalWorkflowCallValidator.default_time_validators
272
289
  } #: Hash[String, :all | Array[Symbol]]
273
290
  hash.each_value(&:freeze)
274
291
  hash.freeze
@@ -292,9 +309,6 @@ module Temporalio
292
309
  # @param interceptors [Array<Interceptor::Activity, Interceptor::Workflow>] Interceptors specific to this worker.
293
310
  # Note, interceptors set on the client that include the {Interceptor::Activity} or {Interceptor::Workflow} module
294
311
  # are automatically included here, so no need to specify them again.
295
- # @param build_id [String] Unique identifier for the current runtime. This is best set as a unique value
296
- # representing all code and should change only when code does. This can be something like a git commit hash. If
297
- # unset, default is hash of known Ruby code.
298
312
  # @param identity [String, nil] Override the identity for this worker. If unset, client identity is used.
299
313
  # @param logger [Logger] Logger to override client logger with. Default is the client logger.
300
314
  # @param max_cached_workflows [Integer] Number of workflows held in cache for use by sticky task queue. If set to 0,
@@ -323,19 +337,19 @@ module Temporalio
323
337
  # multiple workers on the same queue have different values set, they will thrash with the last poller winning.
324
338
  # @param graceful_shutdown_period [Float] Amount of time after shutdown is called that activities are given to
325
339
  # complete before their tasks are canceled.
326
- # @param use_worker_versioning [Boolean] If true, the `build_id` argument must be specified, and this worker opts
327
- # into the worker versioning feature. This ensures it only receives workflow tasks for workflows which it claims
328
- # to be compatible with. For more information, see https://docs.temporal.io/workers#worker-versioning.
329
340
  # @param disable_eager_activity_execution [Boolean] If true, disables eager activity execution. Eager activity
330
341
  # execution is an optimization on some servers that sends activities back to the same worker as the calling
331
342
  # workflow if they can run there. This should be set to true for `max_task_queue_activities_per_second` to work
332
343
  # and in a future version of this API may be implied as such (i.e. this setting will be ignored if that setting is
333
344
  # set).
334
- # @param illegal_workflow_calls [Hash<String, [:all, Array<Symbol>]>] Set of illegal workflow calls that are
335
- # considered unsafe/non-deterministic and will raise if seen. The key of the hash is the fully qualified string
336
- # class name (no leading `::`). The value is either `:all` which means any use of the class, or an array of
337
- # symbols for methods on the class that cannot be used. The methods refer to either instance or class methods,
338
- # there is no way to differentiate at this time.
345
+ # @param illegal_workflow_calls [Hash<String,
346
+ # [:all, Array<Symbol, IllegalWorkflowCallValidator>, IllegalWorkflowCallValidator]>] Set of illegal workflow
347
+ # calls that are considered unsafe/non-deterministic and will raise if seen. The key of the hash is the fully
348
+ # qualified string class name (no leading `::`). The value can be `:all` which means any use of the class is
349
+ # illegal. The value can be an array of symbols/validators for methods on the class that cannot be used. The
350
+ # methods refer to either instance or class methods, there is no way to differentiate at this time. Symbol method
351
+ # names are the normal way to say the method cannot be used, validators are only for advanced situations. Finally,
352
+ # for advanced situations, the hash value can be a class-level validator that is not tied to a specific method.
339
353
  # @param workflow_failure_exception_types [Array<Class<Exception>>] Workflow failure exception types. This is the
340
354
  # set of exception types that, if a workflow-thrown exception extends, will cause the workflow/update to fail
341
355
  # instead of suspending the workflow via task failure. These are applied in addition to the
@@ -344,6 +358,15 @@ module Temporalio
344
358
  # @param workflow_payload_codec_thread_pool [ThreadPool, nil] Thread pool to run payload codec encode/decode within.
345
359
  # This is required if a payload codec exists and the worker is not fiber based. Codecs can potentially block
346
360
  # execution which is why they need to be run in the background.
361
+ # @param unsafe_workflow_io_enabled [Boolean] If false, the default, workflow code that invokes io_wait on the fiber
362
+ # scheduler will fail. Instead of setting this to true, users are encouraged to use {Workflow::Unsafe.io_enabled}
363
+ # with a block for narrower enabling of IO.
364
+ # @param deployment_options [DeploymentOptions, nil] Deployment options for the worker.
365
+ # WARNING: This is an experimental feature and may change in the future.
366
+ # @param workflow_task_poller_behavior [PollerBehavior] Specify the behavior of workflow task
367
+ # polling. Defaults to a 5-poller maximum.
368
+ # @param activity_task_poller_behavior [PollerBehavior] Specify the behavior of activity task
369
+ # polling. Defaults to a 5-poller maximum.
347
370
  # @param debug_mode [Boolean] If true, deadlock detection is disabled. Deadlock detection will fail workflow tasks
348
371
  # if they block the thread for too long. This defaults to true if the `TEMPORAL_DEBUG` environment variable is
349
372
  # `true` or `1`.
@@ -356,7 +379,6 @@ module Temporalio
356
379
  activity_executors: ActivityExecutor.defaults,
357
380
  workflow_executor: WorkflowExecutor::ThreadPool.default,
358
381
  interceptors: [],
359
- build_id: Worker.default_build_id,
360
382
  identity: nil,
361
383
  logger: client.options.logger,
362
384
  max_cached_workflows: 1000,
@@ -370,15 +392,20 @@ module Temporalio
370
392
  max_activities_per_second: nil,
371
393
  max_task_queue_activities_per_second: nil,
372
394
  graceful_shutdown_period: 0,
373
- use_worker_versioning: false,
374
395
  disable_eager_activity_execution: false,
375
396
  illegal_workflow_calls: Worker.default_illegal_workflow_calls,
376
397
  workflow_failure_exception_types: [],
377
398
  workflow_payload_codec_thread_pool: nil,
399
+ unsafe_workflow_io_enabled: false,
400
+ deployment_options: Worker.default_deployment_options,
401
+ workflow_task_poller_behavior: PollerBehavior::SimpleMaximum.new(max_concurrent_workflow_task_polls),
402
+ activity_task_poller_behavior: PollerBehavior::SimpleMaximum.new(max_concurrent_activity_task_polls),
378
403
  debug_mode: %w[true 1].include?(ENV['TEMPORAL_DEBUG'].to_s.downcase)
379
404
  )
380
405
  raise ArgumentError, 'Must have at least one activity or workflow' if activities.empty? && workflows.empty?
381
406
 
407
+ Internal::ProtoUtils.assert_non_reserved_name(task_queue)
408
+
382
409
  @options = Options.new(
383
410
  client:,
384
411
  task_queue:,
@@ -388,7 +415,6 @@ module Temporalio
388
415
  activity_executors:,
389
416
  workflow_executor:,
390
417
  interceptors:,
391
- build_id:,
392
418
  identity:,
393
419
  logger:,
394
420
  max_cached_workflows:,
@@ -402,16 +428,25 @@ module Temporalio
402
428
  max_activities_per_second:,
403
429
  max_task_queue_activities_per_second:,
404
430
  graceful_shutdown_period:,
405
- use_worker_versioning:,
406
431
  disable_eager_activity_execution:,
407
432
  illegal_workflow_calls:,
408
433
  workflow_failure_exception_types:,
409
434
  workflow_payload_codec_thread_pool:,
435
+ unsafe_workflow_io_enabled:,
436
+ deployment_options:,
437
+ workflow_task_poller_behavior:,
438
+ activity_task_poller_behavior:,
410
439
  debug_mode:
411
440
  ).freeze
412
441
 
442
+ should_enforce_versioning_behavior =
443
+ deployment_options.use_worker_versioning &&
444
+ deployment_options.default_versioning_behavior == VersioningBehavior::UNSPECIFIED
413
445
  # Preload workflow definitions and some workflow settings for the bridge
414
- workflow_definitions = Internal::Worker::WorkflowWorker.workflow_definitions(workflows)
446
+ workflow_definitions = Internal::Worker::WorkflowWorker.workflow_definitions(
447
+ workflows,
448
+ should_enforce_versioning_behavior: should_enforce_versioning_behavior
449
+ )
415
450
  nondeterminism_as_workflow_fail, nondeterminism_as_workflow_fail_for_types =
416
451
  Internal::Worker::WorkflowWorker.bridge_workflow_failure_exception_type_options(
417
452
  workflow_failure_exception_types:, workflow_definitions:
@@ -426,12 +461,11 @@ module Temporalio
426
461
  namespace: client.namespace,
427
462
  task_queue:,
428
463
  tuner: tuner._to_bridge_options,
429
- build_id:,
430
464
  identity_override: identity,
431
465
  max_cached_workflows:,
432
- max_concurrent_workflow_task_polls:,
466
+ workflow_task_poller_behavior: workflow_task_poller_behavior._to_bridge_options,
433
467
  nonsticky_to_sticky_poll_ratio:,
434
- max_concurrent_activity_task_polls:,
468
+ activity_task_poller_behavior: activity_task_poller_behavior._to_bridge_options,
435
469
  # For shutdown to work properly, we must disable remote activities
436
470
  # ourselves if there are no activities
437
471
  no_remote_activities: no_remote_activities || activities.empty?,
@@ -441,9 +475,9 @@ module Temporalio
441
475
  max_worker_activities_per_second: max_activities_per_second,
442
476
  max_task_queue_activities_per_second:,
443
477
  graceful_shutdown_period:,
444
- use_worker_versioning:,
445
478
  nondeterminism_as_workflow_fail:,
446
- nondeterminism_as_workflow_fail_for_types:
479
+ nondeterminism_as_workflow_fail_for_types:,
480
+ deployment_options: deployment_options._to_bridge_options
447
481
  )
448
482
  )
449
483
 
@@ -478,12 +512,17 @@ module Temporalio
478
512
  illegal_workflow_calls:,
479
513
  workflow_failure_exception_types:,
480
514
  workflow_payload_codec_thread_pool:,
481
- debug_mode:
515
+ unsafe_workflow_io_enabled:,
516
+ debug_mode:,
517
+ assert_valid_local_activity: ->(activity) { _assert_valid_local_activity(activity) }
482
518
  )
483
519
  end
484
520
 
485
521
  # Validate worker
486
522
  @bridge_worker.validate
523
+
524
+ # Mutex needed for accessing and replacing a client
525
+ @client_mutex = Mutex.new
487
526
  end
488
527
 
489
528
  # @return [String] Task queue set on the worker options.
@@ -491,6 +530,25 @@ module Temporalio
491
530
  @options.task_queue
492
531
  end
493
532
 
533
+ # @return [Client] Client for this worker. This is the same as {Options.client} in {options}, but surrounded by a
534
+ # mutex to be safe for client replacement in {client=}.
535
+ def client
536
+ @client_mutex.synchronize { @options.client }
537
+ end
538
+
539
+ # Replace the worker's client. When this is called, the client is replaced on the internal worker which means any
540
+ # new calls will be made on the new client (but existing calls will still complete on the previous one). This is
541
+ # commonly used for providing a new client with updated authentication credentials.
542
+ #
543
+ # @param new_client [Client] New client to use for new calls.
544
+ def client=(new_client)
545
+ @client_mutex.synchronize do
546
+ @bridge_worker.replace_client(new_client.connection._core_client)
547
+ @options = @options.with(client: new_client)
548
+ new_client
549
+ end
550
+ end
551
+
494
552
  # Run this worker until cancellation or optional block completes. When the cancellation or block is complete, the
495
553
  # worker is shut down. This will return the block result if everything successful or raise an error if not.
496
554
  #
@@ -565,5 +623,17 @@ module Temporalio
565
623
  @workflow_worker&.on_shutdown_complete
566
624
  @workflow_worker = nil
567
625
  end
626
+
627
+ # @!visibility private
628
+ def _assert_valid_local_activity(activity)
629
+ unless @activity_worker.nil?
630
+ @activity_worker.assert_valid_activity(activity)
631
+ return
632
+ end
633
+
634
+ raise ArgumentError,
635
+ "Activity #{activity} " \
636
+ 'is not registered on this worker, no available activities.'
637
+ end
568
638
  end
569
639
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/internal/bridge/worker'
4
+
5
+ module Temporalio
6
+ WorkerDeploymentVersion = Data.define(
7
+ :deployment_name,
8
+ :build_id
9
+ )
10
+
11
+ # Represents the version of a specific worker deployment.
12
+ #
13
+ # WARNING: Experimental API.
14
+ class WorkerDeploymentVersion
15
+ # Parse a version from a canonical string, which must be in the format
16
+ # `<deployment_name>.<build_id>`. Deployment name must not have a `.` in it.
17
+ #
18
+ # @param canonical [String] The canonical string representation of the version.
19
+ # @return [WorkerDeploymentVersion] The parsed version.
20
+ def self.from_canonical_string(canonical)
21
+ parts = canonical.split('.', 2)
22
+ if parts.length != 2
23
+ raise ArgumentError,
24
+ "Cannot parse version string: #{canonical}, must be in format <deployment_name>.<build_id>"
25
+ end
26
+ new(deployment_name: parts[0], build_id: parts[1])
27
+ end
28
+
29
+ # @!visibility private
30
+ def self._from_bridge(bridge)
31
+ return nil if bridge.nil?
32
+
33
+ new(deployment_name: bridge.deployment_name, build_id: bridge.build_id)
34
+ end
35
+
36
+ # Create WorkerDeploymentVersion.
37
+ #
38
+ # @param deployment_name [String] The name of the deployment.
39
+ # @param build_id [String] The build identifier specific to this worker build.
40
+ def initialize(deployment_name:, build_id:) # rubocop:disable Lint/UselessMethodDefinition
41
+ super
42
+ end
43
+
44
+ # Returns the canonical string representation of the version.
45
+ #
46
+ # @return [String]
47
+ def to_canonical_string
48
+ "#{deployment_name}.#{build_id}"
49
+ end
50
+
51
+ # @!visibility private
52
+ def _to_bridge_options
53
+ Internal::Bridge::Worker::WorkerDeploymentVersion.new(
54
+ deployment_name: deployment_name,
55
+ build_id: build_id
56
+ )
57
+ end
58
+
59
+ # @!visibility private
60
+ def _to_proto
61
+ Api::Deployment::V1::WorkerDeploymentVersion.new(
62
+ deployment_name: deployment_name,
63
+ build_id: build_id
64
+ )
65
+ end
66
+ end
67
+ end