temporalio 1.0.0-aarch64-linux-musl → 1.2.0-aarch64-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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -4
  3. data/lib/temporalio/activity/definition.rb +6 -1
  4. data/lib/temporalio/api/activity/v1/message.rb +11 -2
  5. data/lib/temporalio/api/cloud/account/v1/message.rb +3 -1
  6. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +5 -1
  7. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
  8. data/lib/temporalio/api/cloud/sink/v1/message.rb +3 -1
  9. data/lib/temporalio/api/command/v1/message.rb +1 -1
  10. data/lib/temporalio/api/common/v1/message.rb +2 -1
  11. data/lib/temporalio/api/deployment/v1/message.rb +2 -1
  12. data/lib/temporalio/api/enums/v1/activity.rb +23 -0
  13. data/lib/temporalio/api/enums/v1/event_type.rb +1 -1
  14. data/lib/temporalio/api/enums/v1/failed_cause.rb +1 -1
  15. data/lib/temporalio/api/enums/v1/task_queue.rb +2 -1
  16. data/lib/temporalio/api/enums/v1/workflow.rb +3 -1
  17. data/lib/temporalio/api/errordetails/v1/message.rb +2 -1
  18. data/lib/temporalio/api/history/v1/message.rb +3 -1
  19. data/lib/temporalio/api/namespace/v1/message.rb +2 -1
  20. data/lib/temporalio/api/nexus/v1/message.rb +1 -1
  21. data/lib/temporalio/api/operatorservice/v1/request_response.rb +1 -1
  22. data/lib/temporalio/api/payload_visitor.rb +70 -0
  23. data/lib/temporalio/api/taskqueue/v1/message.rb +1 -1
  24. data/lib/temporalio/api/worker/v1/message.rb +1 -1
  25. data/lib/temporalio/api/workflow/v1/message.rb +2 -1
  26. data/lib/temporalio/api/workflowservice/v1/request_response.rb +27 -1
  27. data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
  28. data/lib/temporalio/client/connection/cloud_service.rb +30 -0
  29. data/lib/temporalio/client/connection/workflow_service.rb +180 -0
  30. data/lib/temporalio/client/connection.rb +31 -12
  31. data/lib/temporalio/client/plugin.rb +42 -0
  32. data/lib/temporalio/client.rb +83 -14
  33. data/lib/temporalio/contrib/open_telemetry.rb +78 -25
  34. data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +4 -1
  35. data/lib/temporalio/converters/payload_converter/composite.rb +1 -0
  36. data/lib/temporalio/converters/payload_converter/json_protobuf.rb +5 -2
  37. data/lib/temporalio/env_config.rb +3 -12
  38. data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
  39. data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
  40. data/lib/temporalio/internal/bridge/{3.2 → 4.0}/temporalio_bridge.so +0 -0
  41. data/lib/temporalio/internal/bridge/api/core_interface.rb +3 -1
  42. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +2 -1
  43. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +1 -1
  44. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +1 -1
  45. data/lib/temporalio/internal/bridge/runtime.rb +1 -0
  46. data/lib/temporalio/internal/bridge/worker.rb +5 -3
  47. data/lib/temporalio/internal/worker/workflow_instance/context.rb +4 -0
  48. data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +1 -1
  49. data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +1 -1
  50. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +8 -4
  51. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +32 -11
  52. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +2 -1
  53. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +2 -1
  54. data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +10 -1
  55. data/lib/temporalio/internal/worker/workflow_instance.rb +16 -11
  56. data/lib/temporalio/runtime.rb +16 -3
  57. data/lib/temporalio/simple_plugin.rb +192 -0
  58. data/lib/temporalio/version.rb +1 -1
  59. data/lib/temporalio/worker/plugin.rb +88 -0
  60. data/lib/temporalio/worker/tuner.rb +0 -4
  61. data/lib/temporalio/worker/workflow_replayer.rb +32 -8
  62. data/lib/temporalio/worker.rb +117 -44
  63. data/lib/temporalio/workflow/definition.rb +3 -1
  64. data/lib/temporalio/workflow/info.rb +4 -0
  65. data/lib/temporalio/workflow.rb +8 -1
  66. data/temporalio.gemspec +1 -1
  67. metadata +9 -5
@@ -7,8 +7,6 @@ module Temporalio
7
7
  module Bridge
8
8
  class Worker
9
9
  Options = Struct.new(
10
- :activity,
11
- :workflow,
12
10
  :namespace,
13
11
  :task_queue,
14
12
  :tuner,
@@ -17,7 +15,10 @@ module Temporalio
17
15
  :workflow_task_poller_behavior,
18
16
  :nonsticky_to_sticky_poll_ratio,
19
17
  :activity_task_poller_behavior,
20
- :no_remote_activities,
18
+ :enable_workflows,
19
+ :enable_local_activities,
20
+ :enable_remote_activities,
21
+ :enable_nexus,
21
22
  :sticky_queue_schedule_to_start_timeout,
22
23
  :max_heartbeat_throttle_interval,
23
24
  :default_heartbeat_throttle_interval,
@@ -27,6 +28,7 @@ module Temporalio
27
28
  :nondeterminism_as_workflow_fail,
28
29
  :nondeterminism_as_workflow_fail_for_types,
29
30
  :deployment_options,
31
+ :plugins,
30
32
  keyword_init: true
31
33
  )
32
34
 
@@ -242,6 +242,10 @@ module Temporalio
242
242
  @instance.replaying
243
243
  end
244
244
 
245
+ def replaying_history_events?
246
+ @instance.replaying && !@instance.in_query_or_validator
247
+ end
248
+
245
249
  def search_attributes
246
250
  @instance.search_attributes
247
251
  end
@@ -9,7 +9,7 @@ module Temporalio
9
9
  # Delegator to a hash that does not allow external mutations. Used for memo.
10
10
  class ExternallyImmutableHash < SimpleDelegator
11
11
  def initialize(initial_hash)
12
- super(initial_hash.freeze)
12
+ super(initial_hash.freeze) # steep:ignore ArgumentTypeMismatch
13
13
  end
14
14
 
15
15
  def _update(&)
@@ -7,7 +7,7 @@ module Temporalio
7
7
  # Hash for handlers that notifies when one is added. Only `[]=` and `store` can be used to mutate it.
8
8
  class HandlerHash < SimpleDelegator
9
9
  def initialize(initial_frozen_hash, definition_class, &on_new_definition)
10
- super(initial_frozen_hash)
10
+ super(initial_frozen_hash) # steep:ignore ArgumentTypeMismatch
11
11
  @definition_class = definition_class
12
12
  @on_new_definition = on_new_definition
13
13
  end
@@ -13,7 +13,7 @@ module Temporalio
13
13
  illegal_calls.to_h do |key, val|
14
14
  raise TypeError, 'Invalid illegal call map, top-level key must be a String' unless key.is_a?(String)
15
15
 
16
- # @type var fixed_val: :all | Worker::IllegalWorkflowCallValidator | Hash[Symbol, TrueClass | Worker::IllegalWorkflowCallValidator] # rubocop:disable Layout/LineLength
16
+ # @type var fixed_val: :all | Temporalio::Worker::IllegalWorkflowCallValidator | Hash[Symbol, (true | Temporalio::Worker::IllegalWorkflowCallValidator)]
17
17
  fixed_val = case val
18
18
  when Temporalio::Worker::IllegalWorkflowCallValidator
19
19
  if val.method_name
@@ -86,21 +86,25 @@ module Temporalio
86
86
  when Temporalio::Worker::IllegalWorkflowCallValidator
87
87
  disable_temporarily do
88
88
  vals.block.call(Temporalio::Worker::IllegalWorkflowCallValidator::CallInfo.new(
89
- class_name:, method_name: tp.callee_id, trace_point: tp
89
+ class_name:,
90
+ method_name: tp.callee_id || :__unknown__,
91
+ trace_point: tp
90
92
  ))
91
93
  nil
92
94
  rescue Exception => e # rubocop:disable Lint/RescueException
93
95
  ", reason: #{e}"
94
96
  end
95
97
  else
96
- per_method = vals&.[](tp.callee_id)
98
+ per_method = vals&.[](tp.callee_id || :__unknown__)
97
99
  case per_method
98
100
  when true
99
101
  ''
100
102
  when Temporalio::Worker::IllegalWorkflowCallValidator
101
103
  disable_temporarily do
102
104
  per_method.block.call(Temporalio::Worker::IllegalWorkflowCallValidator::CallInfo.new(
103
- class_name:, method_name: tp.callee_id, trace_point: tp
105
+ class_name:,
106
+ method_name: tp.callee_id || :__unknown__,
107
+ trace_point: tp
104
108
  ))
105
109
  nil
106
110
  rescue Exception => e # rubocop:disable Lint/RescueException
@@ -43,7 +43,12 @@ module Temporalio
43
43
  @instance.pending_external_cancels[seq] = Fiber.current
44
44
 
45
45
  # Wait
46
- resolution = Fiber.yield
46
+ resolution = begin
47
+ Fiber.yield
48
+ ensure
49
+ # Remove pending
50
+ @instance.pending_external_cancels.delete(seq)
51
+ end
47
52
 
48
53
  # Raise if resolution has failure
49
54
  return unless resolution.failure
@@ -169,10 +174,13 @@ module Temporalio
169
174
  end
170
175
 
171
176
  # Wait
172
- resolution = Fiber.yield
173
-
174
- # Remove cancellation callback
175
- cancellation.remove_cancel_callback(cancel_callback_key)
177
+ resolution = begin
178
+ Fiber.yield
179
+ ensure
180
+ # Remove pending and cancel callback
181
+ @instance.pending_activities.delete(seq)
182
+ cancellation.remove_cancel_callback(cancel_callback_key)
183
+ end
176
184
 
177
185
  case resolution.status
178
186
  when :completed
@@ -254,10 +262,13 @@ module Temporalio
254
262
  end
255
263
 
256
264
  # Wait
257
- resolution = Fiber.yield
258
-
259
- # Remove cancellation callback
260
- cancellation.remove_cancel_callback(cancel_callback_key)
265
+ resolution = begin
266
+ Fiber.yield
267
+ ensure
268
+ # Remove pending and cancel callback
269
+ @instance.pending_external_signals.delete(seq)
270
+ cancellation.remove_cancel_callback(cancel_callback_key)
271
+ end
261
272
 
262
273
  # Raise if resolution has failure
263
274
  return unless resolution.failure
@@ -317,7 +328,12 @@ module Temporalio
317
328
  end
318
329
 
319
330
  # Wait
320
- Fiber.yield
331
+ begin
332
+ Fiber.yield
333
+ ensure
334
+ # Remove pending
335
+ @instance.pending_timers.delete(seq)
336
+ end
321
337
 
322
338
  # Remove cancellation callback (only needed on success)
323
339
  input.cancellation.remove_cancel_callback(cancel_callback_key)
@@ -374,7 +390,12 @@ module Temporalio
374
390
  end
375
391
 
376
392
  # Wait for start
377
- resolution = Fiber.yield
393
+ resolution = begin
394
+ Fiber.yield
395
+ ensure
396
+ # Remove pending
397
+ @instance.pending_child_workflow_starts.delete(seq)
398
+ end
378
399
 
379
400
  case resolution.status
380
401
  when :succeeded
@@ -23,7 +23,8 @@ module Temporalio
23
23
  end
24
24
 
25
25
  def add(...)
26
- if !@replay_safety_disabled && Temporalio::Workflow.in_workflow? && Temporalio::Workflow::Unsafe.replaying?
26
+ if !@replay_safety_disabled && Temporalio::Workflow.in_workflow? &&
27
+ Temporalio::Workflow::Unsafe.replaying_history_events?
27
28
  return true
28
29
  end
29
30
 
@@ -9,7 +9,8 @@ module Temporalio
9
9
  # Wrapper for a metric that does not log on replay.
10
10
  class ReplaySafeMetric < SimpleDelegator
11
11
  def record(value, additional_attributes: nil)
12
- return if Temporalio::Workflow.in_workflow? && Temporalio::Workflow::Unsafe.replaying?
12
+ return if Temporalio::Workflow.in_workflow? &&
13
+ Temporalio::Workflow::Unsafe.replaying_history_events?
13
14
 
14
15
  super
15
16
  end
@@ -78,7 +78,12 @@ module Temporalio
78
78
  end
79
79
 
80
80
  # This blocks until a resume is called on this fiber
81
- result = Fiber.yield
81
+ result = begin
82
+ Fiber.yield
83
+ ensure
84
+ # Remove pending
85
+ @wait_conditions.delete(seq)
86
+ end
82
87
 
83
88
  # Remove cancellation callback (only needed on success)
84
89
  cancellation&.remove_cancel_callback(cancel_callback_key) if cancel_callback_key
@@ -141,6 +146,10 @@ module Temporalio
141
146
  fiber
142
147
  end
143
148
 
149
+ def fiber_interrupt(fiber, exception)
150
+ fiber.raise(exception) if fiber.alive?
151
+ end
152
+
144
153
  def io_wait(io, events, timeout)
145
154
  # Do not allow if IO disabled
146
155
  unless @instance.io_enabled
@@ -57,7 +57,8 @@ module Temporalio
57
57
  :pending_external_signals, :pending_external_cancels, :in_progress_handlers, :payload_converter,
58
58
  :failure_converter, :cancellation, :continue_as_new_suggested, :current_deployment_version,
59
59
  :current_history_length, :current_history_size, :replaying, :random,
60
- :signal_handlers, :query_handlers, :update_handlers, :context_frozen, :assert_valid_local_activity
60
+ :signal_handlers, :query_handlers, :update_handlers, :context_frozen, :assert_valid_local_activity,
61
+ :in_query_or_validator
61
62
  attr_accessor :io_enabled, :current_details
62
63
 
63
64
  def initialize(details)
@@ -91,6 +92,7 @@ module Temporalio
91
92
  @current_history_length = 0
92
93
  @current_history_size = 0
93
94
  @replaying = false
95
+ @in_query_or_validator = false
94
96
  @workflow_failure_exception_types = details.workflow_failure_exception_types
95
97
  @signal_handlers = HandlerHash.new(
96
98
  details.definition.signals,
@@ -133,6 +135,7 @@ module Temporalio
133
135
  last_result: if @init_job.last_completion_result
134
136
  @payload_converter.from_payloads(@init_job.last_completion_result).first
135
137
  end,
138
+ has_last_result?: !@init_job.last_completion_result.nil?,
136
139
  namespace: details.namespace,
137
140
  parent: if @init_job.parent_workflow_info
138
141
  Workflow::Info::ParentInfo.new(
@@ -181,7 +184,7 @@ module Temporalio
181
184
  # Apply jobs and run event loop
182
185
  begin
183
186
  # Create instance if it doesn't already exist
184
- @instance ||= with_context_frozen { create_instance }
187
+ @instance ||= with_context_frozen(in_query_or_validator: false) { create_instance }
185
188
 
186
189
  # Apply jobs
187
190
  activation.jobs.each { |job| apply(job) }
@@ -344,7 +347,7 @@ module Temporalio
344
347
  when :initialize_workflow
345
348
  # Ignore
346
349
  when :fire_timer
347
- pending_timers.delete(job.fire_timer.seq)&.resume
350
+ pending_timers[job.fire_timer.seq]&.resume
348
351
  when :update_random_seed
349
352
  @random = illegal_call_tracing_disabled { Random.new(job.update_random_seed.randomness_seed) }
350
353
  when :query_workflow
@@ -355,23 +358,23 @@ module Temporalio
355
358
  when :signal_workflow
356
359
  apply_signal(job.signal_workflow)
357
360
  when :resolve_activity
358
- pending_activities.delete(job.resolve_activity.seq)&.resume(job.resolve_activity.result)
361
+ pending_activities[job.resolve_activity.seq]&.resume(job.resolve_activity.result)
359
362
  when :notify_has_patch
360
363
  @patches_notified << job.notify_has_patch.patch_id
361
364
  when :resolve_child_workflow_execution_start
362
- pending_child_workflow_starts.delete(job.resolve_child_workflow_execution_start.seq)&.resume(
365
+ pending_child_workflow_starts[job.resolve_child_workflow_execution_start.seq]&.resume(
363
366
  job.resolve_child_workflow_execution_start
364
367
  )
365
368
  when :resolve_child_workflow_execution
366
- pending_child_workflows.delete(job.resolve_child_workflow_execution.seq)&._resolve(
369
+ pending_child_workflows[job.resolve_child_workflow_execution.seq]&._resolve(
367
370
  job.resolve_child_workflow_execution.result
368
371
  )
369
372
  when :resolve_signal_external_workflow
370
- pending_external_signals.delete(job.resolve_signal_external_workflow.seq)&.resume(
373
+ pending_external_signals[job.resolve_signal_external_workflow.seq]&.resume(
371
374
  job.resolve_signal_external_workflow
372
375
  )
373
376
  when :resolve_request_cancel_external_workflow
374
- pending_external_cancels.delete(job.resolve_request_cancel_external_workflow.seq)&.resume(
377
+ pending_external_cancels[job.resolve_request_cancel_external_workflow.seq]&.resume(
375
378
  job.resolve_request_cancel_external_workflow
376
379
  )
377
380
  when :do_update
@@ -438,7 +441,7 @@ module Temporalio
438
441
  end
439
442
  result_hint = defn.result_hint
440
443
 
441
- with_context_frozen do
444
+ with_context_frozen(in_query_or_validator: true) do
442
445
  @inbound.handle_query(
443
446
  Temporalio::Worker::Interceptor::Workflow::HandleQueryInput.new(
444
447
  id: job.query_id,
@@ -501,7 +504,7 @@ module Temporalio
501
504
  # other SDKs, we are re-converting the args between validate and update to disallow user mutation in
502
505
  # validator/interceptor.
503
506
  if job.run_validator && defn.validator_to_invoke
504
- with_context_frozen do
507
+ with_context_frozen(in_query_or_validator: true) do
505
508
  @inbound.validate_update(
506
509
  Temporalio::Worker::Interceptor::Workflow::HandleUpdateInput.new(
507
510
  id: job.id,
@@ -662,11 +665,13 @@ module Temporalio
662
665
  @definition_options.failure_exception_types&.any? { |cls| err.is_a?(cls) }
663
666
  end
664
667
 
665
- def with_context_frozen(&)
668
+ def with_context_frozen(in_query_or_validator:, &)
666
669
  @context_frozen = true
670
+ @in_query_or_validator = in_query_or_validator
667
671
  yield
668
672
  ensure
669
673
  @context_frozen = false
674
+ @in_query_or_validator = false
670
675
  end
671
676
 
672
677
  def convert_handler_args(payload_array:, defn:)
@@ -101,7 +101,8 @@ module Temporalio
101
101
  # @!visibility private
102
102
  def _to_bridge
103
103
  # @type self: LoggingFilterOptions
104
- "#{other_level},temporal_sdk_core=#{core_level},temporal_client=#{core_level},temporal_sdk=#{core_level}"
104
+ "#{other_level},temporalio_sdk_core=#{core_level},temporalio_client=#{core_level}," \
105
+ "temporalio_sdk=#{core_level},temporalio_bridge=#{core_level}"
105
106
  end
106
107
  end
107
108
 
@@ -329,12 +330,24 @@ module Temporalio
329
330
  # pool, this also consumes a Ruby thread for its lifetime.
330
331
  #
331
332
  # @param telemetry [TelemetryOptions] Telemetry options to set.
332
- def initialize(telemetry: TelemetryOptions.new)
333
+ # @param worker_heartbeat_interval [Float, nil] Interval for worker heartbeats in seconds. Can be nil to disable
334
+ # heartbeating. Interval must be between 1s and 60s.
335
+ def initialize(
336
+ telemetry: TelemetryOptions.new,
337
+ worker_heartbeat_interval: 60
338
+ )
339
+ if !worker_heartbeat_interval.nil? && !worker_heartbeat_interval.positive?
340
+ raise 'Worker heartbeat interval must be positive'
341
+ end
342
+
333
343
  # Set runtime on the buffer which will fail if the buffer is used on another runtime
334
344
  telemetry.metrics&.buffer&._set_runtime(self)
335
345
 
336
346
  @core_runtime = Internal::Bridge::Runtime.new(
337
- Internal::Bridge::Runtime::Options.new(telemetry: telemetry._to_bridge)
347
+ Internal::Bridge::Runtime::Options.new(
348
+ telemetry: telemetry._to_bridge,
349
+ worker_heartbeat_interval:
350
+ )
338
351
  )
339
352
  @metric_meter = Internal::Metric::Meter.create_from_runtime(self) || Metric::Meter.null
340
353
  # We need a thread to run the command loop
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/client'
4
+ require 'temporalio/worker'
5
+
6
+ module Temporalio
7
+ # Plugin that implements both {Client::Plugin} and {Worker::Plugin} and provides a simplified common set of settings
8
+ # for configuring both.
9
+ #
10
+ # WARNING: Plugins are experimental.
11
+ class SimplePlugin
12
+ include Client::Plugin
13
+ include Worker::Plugin
14
+
15
+ Options = Data.define(
16
+ :name,
17
+ :data_converter,
18
+ :client_interceptors,
19
+ :activities,
20
+ :workflows,
21
+ :worker_interceptors,
22
+ :workflow_failure_exception_types,
23
+ :run_context
24
+ )
25
+
26
+ # Options as returned from {options} representing the options passed to the constructor.
27
+ class Options; end # rubocop:disable Lint/EmptyClass
28
+
29
+ # @return [Options] Frozen options for this plugin which has the same attributes as {initialize}.
30
+ attr_reader :options
31
+
32
+ # Create a simple plugin.
33
+ #
34
+ # @param name [String] Required string name for this plugin.
35
+ # @param data_converter [Converters::DataConverter, Proc, nil] Data converter to apply to clients and workflow
36
+ # replayers. This can be a proc that accepts the existing data converter and returns a new one.
37
+ # @param client_interceptors [Array<Client::Integerceptor>, Proc, nil] Client interceptors that are appended to the
38
+ # existing client set (which means if they implement worker interceptors they are applied for the workers too). A
39
+ # proc can be provided that accepts the existing array and returns a new one.
40
+ # @param activities [Array<Activity::Definition, Class<Activity::Definition>, Activity::Definition::Info>, Proc,
41
+ # nil] Activities to append to each worker activity set. A proc can be provided that accepts the existing array
42
+ # and returns a new one.
43
+ # @param workflows [Array<Class<Workflow::Definition>>, Proc, nil] Workflows to append to each worker workflow set.
44
+ # A proc can be provided that accepts the existing array and returns a new one.
45
+ # @param worker_interceptors [Array<Interceptor::Activity, Interceptor::Workflow>, Proc, nil] Worker interceptors
46
+ # that are appended to the existing worker or workflow replayer set. A proc can be provided that accepts the
47
+ # existing array and returns a new one.
48
+ # @param workflow_failure_exception_types [Array<Class<Exception>>] Workflow failure exception types that are
49
+ # appended to the existing worker or workflow replayer set. A proc can be provided that accepts the existing array
50
+ # and returns a new one.
51
+ # @param run_context [Proc, nil] A proc that intercepts both {run_worker} or {with_workflow_replay_worker}. The proc
52
+ # should accept two positional parameters: options and next_call. The options are either
53
+ # {Worker::Plugin::RunWorkerOptions} or {Worker::Plugin::WithWorkflowReplayWorkerOptions}. The next_call is a proc
54
+ # itself that accepts the options and returns a value. This run_context proc should return the result of the
55
+ # next_call.
56
+ def initialize(
57
+ name:,
58
+ data_converter: nil,
59
+ client_interceptors: nil,
60
+ activities: nil,
61
+ workflows: nil,
62
+ worker_interceptors: nil,
63
+ workflow_failure_exception_types: nil,
64
+ run_context: nil
65
+ )
66
+ @options = Options.new(
67
+ name:,
68
+ data_converter:,
69
+ client_interceptors:,
70
+ activities:,
71
+ workflows:,
72
+ worker_interceptors:,
73
+ workflow_failure_exception_types:,
74
+ run_context:
75
+ ).freeze
76
+ end
77
+
78
+ # Implements {Client::Plugin#name} and {Worker::Plugin#name}.
79
+ def name
80
+ @options.name
81
+ end
82
+
83
+ # Implements {Client::Plugin#configure_client}.
84
+ def configure_client(options)
85
+ if (data_converter = _single_option(new: @options.data_converter, existing: options.data_converter,
86
+ type: Converters::DataConverter, name: 'data converter'))
87
+ options = options.with(data_converter:)
88
+ end
89
+ if (interceptors = _array_option(new: @options.client_interceptors, existing: options.interceptors,
90
+ name: 'client interceptor'))
91
+ options = options.with(interceptors:)
92
+ end
93
+ options
94
+ end
95
+
96
+ # Implements {Client::Plugin#connect_client}.
97
+ def connect_client(options, next_call)
98
+ next_call.call(options)
99
+ end
100
+
101
+ # Implements {Worker::Plugin#configure_worker}.
102
+ def configure_worker(options)
103
+ if (activities = _array_option(new: @options.activities, existing: options.activities, name: 'activity'))
104
+ options = options.with(activities:)
105
+ end
106
+ if (workflows = _array_option(new: @options.workflows, existing: options.workflows, name: 'workflow'))
107
+ options = options.with(workflows:)
108
+ end
109
+ if (interceptors = _array_option(new: @options.worker_interceptors, existing: options.interceptors,
110
+ name: 'worker interceptor'))
111
+ options = options.with(interceptors:)
112
+ end
113
+ if (workflow_failure_exception_types = _array_option(new: @options.workflow_failure_exception_types,
114
+ existing: options.workflow_failure_exception_types,
115
+ name: 'workflow failure exception types'))
116
+ options = options.with(workflow_failure_exception_types:)
117
+ end
118
+ options
119
+ end
120
+
121
+ # Implements {Worker::Plugin#run_worker}.
122
+ def run_worker(options, next_call)
123
+ if @options.run_context
124
+ @options.run_context.call(options, next_call) # steep:ignore NoMethod
125
+ else
126
+ next_call.call(options)
127
+ end
128
+ end
129
+
130
+ # Implements {Worker::Plugin#configure_workflow_replayer}.
131
+ def configure_workflow_replayer(options)
132
+ if (data_converter = _single_option(new: @options.data_converter, existing: options.data_converter,
133
+ type: Converters::DataConverter, name: 'data converter'))
134
+ options = options.with(data_converter:)
135
+ end
136
+ if (workflows = _array_option(new: @options.workflows, existing: options.workflows, name: 'workflow'))
137
+ options = options.with(workflows:)
138
+ end
139
+ if (interceptors = _array_option(new: @options.worker_interceptors, existing: options.interceptors,
140
+ name: 'worker interceptor'))
141
+ options = options.with(interceptors:)
142
+ end
143
+ if (workflow_failure_exception_types = _array_option(new: @options.workflow_failure_exception_types,
144
+ existing: options.workflow_failure_exception_types,
145
+ name: 'workflow failure exception types'))
146
+ options = options.with(workflow_failure_exception_types:)
147
+ end
148
+ options
149
+ end
150
+
151
+ # Implements {Worker::Plugin#with_workflow_replay_worker}.
152
+ def with_workflow_replay_worker(options, next_call)
153
+ if @options.run_context
154
+ @options.run_context.call(options, next_call) # steep:ignore NoMethod
155
+ else
156
+ next_call.call(options)
157
+ end
158
+ end
159
+
160
+ # @!visibility private
161
+ def _single_option(new:, existing:, type:, name:)
162
+ case new
163
+ when nil
164
+ nil
165
+ when Proc
166
+ new.call(existing).tap do |val| # steep:ignore NoMethod
167
+ raise "Instance of #{name} required" unless val.is_a?(type)
168
+ end
169
+ when type
170
+ new
171
+ else
172
+ raise "Unrecognized #{name} type #{new.class}"
173
+ end
174
+ end
175
+
176
+ # @!visibility private
177
+ def _array_option(new:, existing:, name:)
178
+ case new
179
+ when nil
180
+ nil
181
+ when Proc
182
+ new.call(existing).tap do |conv| # steep:ignore NoMethod
183
+ raise "Array for #{name} required" unless conv.is_a?(Array)
184
+ end
185
+ when Array
186
+ existing + new # steep:ignore NoMethod
187
+ else
188
+ raise "Unrecognized #{name} type #{new.class}"
189
+ end
190
+ end
191
+ end
192
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Temporalio
4
- VERSION = '1.0.0'
4
+ VERSION = '1.2.0'
5
5
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Temporalio
4
+ class Worker
5
+ # Plugin mixin to include for configuring workers and workflow replayers, and intercepting the running of them.
6
+ #
7
+ # This is a low-level implementation that requires abstract methods herein to be implemented. Many implementers may
8
+ # prefer {SimplePlugin} which includes this.
9
+ #
10
+ # WARNING: Plugins are experimental.
11
+ module Plugin
12
+ RunWorkerOptions = Data.define(
13
+ :worker,
14
+ :cancellation,
15
+ :shutdown_signals,
16
+ :raise_in_block_on_shutdown
17
+ )
18
+
19
+ # Options for {run_worker}.
20
+ #
21
+ # The options contain the worker and some other options from {Worker#run}/{Worker.run_all}. Unlike other memebers
22
+ # in this class, mutating the worker member before invoking the next call in the chain has no effect.
23
+ #
24
+ # @note Additional required attributes of this class may be added in the future. Users should never instantiate
25
+ # this class, but instead use `with` on it in {run_worker}.
26
+ class RunWorkerOptions; end # rubocop:disable Lint/EmptyClass
27
+
28
+ WithWorkflowReplayWorkerOptions = Data.define(
29
+ :worker
30
+ )
31
+
32
+ # Options for {with_workflow_replay_worker}.
33
+ #
34
+ # @note Additional required attributes of this class may be added in the future. Users should never instantiate
35
+ # this class, but instead use `with` on it in {with_workflow_replay_worker}.
36
+ #
37
+ # @!attribute worker
38
+ # @return [WorkflowReplayer::ReplayWorker] Replay worker.
39
+ class WithWorkflowReplayWorkerOptions; end # rubocop:disable Lint/EmptyClass
40
+
41
+ # @abstract
42
+ # @return [String] Name of the plugin.
43
+ def name
44
+ raise NotImplementedError
45
+ end
46
+
47
+ # Configure a worker.
48
+ #
49
+ # @abstract
50
+ # @param options [Options] Current immutable options set.
51
+ # @return [Options] Options to use, possibly updated from original.
52
+ def configure_worker(options)
53
+ raise NotImplementedError
54
+ end
55
+
56
+ # Run a worker.
57
+ #
58
+ # @abstract
59
+ # @param options [RunWorkerOptions] Current immutable options set.
60
+ # @param next_call [Proc] Proc for the next plugin in the chain to call. It accepts the options and returns an
61
+ # arbitrary object that should also be returned from this method.
62
+ # @return [Object] Result of next_call.
63
+ def run_worker(options, next_call)
64
+ raise NotImplementedError
65
+ end
66
+
67
+ # Configure a workflow replayer.
68
+ #
69
+ # @abstract
70
+ # @param options [WorkflowReplayer::Options] Current immutable options set.
71
+ # @return [WorkflowReplayer::Options] Options to use, possibly updated from original.
72
+ def configure_workflow_replayer(options)
73
+ raise NotImplementedError
74
+ end
75
+
76
+ # Run a replay worker.
77
+ #
78
+ # @abstract
79
+ # @param options [WithWorkflowReplayWorkerOptions] Current immutable options set.
80
+ # @param next_call [Proc] Proc for the next plugin in the chain to call. It accepts the options and returns an
81
+ # arbitrary object that should also be returned from this method.
82
+ # @return [Object] Result of next_call.
83
+ def with_workflow_replay_worker(options, next_call)
84
+ raise NotImplementedError
85
+ end
86
+ end
87
+ end
88
+ end
@@ -32,8 +32,6 @@ module Temporalio
32
32
  end
33
33
 
34
34
  # A slot supplier that will dynamically adjust the number of slots based on resource usage.
35
- #
36
- # @note WARNING: This API is experimental.
37
35
  class ResourceBased < SlotSupplier
38
36
  attr_reader :tuner_options, :slot_options
39
37
 
@@ -66,8 +64,6 @@ module Temporalio
66
64
  #
67
65
  # Users should be cautious when implementing this and make sure it is heavily tested and the documentation for
68
66
  # every method is well understood.
69
- #
70
- # @note WARNING: This API is experimental.
71
67
  class Custom < SlotSupplier
72
68
  # Context provided for slot reservation on custom slot supplier.
73
69
  #