temporalio 0.3.0-aarch64-linux → 0.5.0-aarch64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/Gemfile +4 -0
- data/Rakefile +1 -1
- data/lib/temporalio/activity/cancellation_details.rb +58 -0
- data/lib/temporalio/activity/context.rb +23 -1
- data/lib/temporalio/activity/definition.rb +63 -8
- data/lib/temporalio/activity/info.rb +28 -4
- data/lib/temporalio/activity.rb +2 -0
- data/lib/temporalio/api/activity/v1/message.rb +1 -1
- data/lib/temporalio/api/batch/v1/message.rb +9 -2
- data/lib/temporalio/api/cloud/account/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +11 -2
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +2 -2
- data/lib/temporalio/api/cloud/identity/v1/message.rb +7 -2
- data/lib/temporalio/api/cloud/namespace/v1/message.rb +6 -2
- data/lib/temporalio/api/cloud/nexus/v1/message.rb +3 -2
- data/lib/temporalio/api/cloud/operation/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/region/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/resource/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/sink/v1/message.rb +1 -1
- data/lib/temporalio/api/cloud/usage/v1/message.rb +1 -1
- data/lib/temporalio/api/command/v1/message.rb +2 -2
- data/lib/temporalio/api/common/v1/grpc_status.rb +1 -1
- data/lib/temporalio/api/common/v1/message.rb +4 -2
- data/lib/temporalio/api/deployment/v1/message.rb +39 -0
- data/lib/temporalio/api/enums/v1/batch_operation.rb +2 -2
- data/lib/temporalio/api/enums/v1/command_type.rb +1 -1
- data/lib/temporalio/api/enums/v1/common.rb +5 -2
- data/lib/temporalio/api/enums/v1/deployment.rb +24 -0
- data/lib/temporalio/api/enums/v1/event_type.rb +2 -2
- data/lib/temporalio/api/enums/v1/failed_cause.rb +2 -2
- data/lib/temporalio/api/enums/v1/namespace.rb +1 -1
- data/lib/temporalio/api/enums/v1/nexus.rb +21 -0
- data/lib/temporalio/api/enums/v1/query.rb +1 -1
- data/lib/temporalio/api/enums/v1/reset.rb +2 -2
- data/lib/temporalio/api/enums/v1/schedule.rb +1 -1
- data/lib/temporalio/api/enums/v1/task_queue.rb +1 -1
- data/lib/temporalio/api/enums/v1/update.rb +1 -1
- data/lib/temporalio/api/enums/v1/workflow.rb +3 -2
- data/lib/temporalio/api/errordetails/v1/message.rb +4 -2
- data/lib/temporalio/api/export/v1/message.rb +1 -1
- data/lib/temporalio/api/failure/v1/message.rb +5 -2
- data/lib/temporalio/api/filter/v1/message.rb +1 -1
- data/lib/temporalio/api/history/v1/message.rb +6 -2
- data/lib/temporalio/api/namespace/v1/message.rb +1 -1
- data/lib/temporalio/api/nexus/v1/message.rb +3 -2
- data/lib/temporalio/api/operatorservice/v1/request_response.rb +1 -1
- data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
- data/lib/temporalio/api/payload_visitor.rb +162 -7
- data/lib/temporalio/api/protocol/v1/message.rb +1 -1
- data/lib/temporalio/api/query/v1/message.rb +3 -2
- data/lib/temporalio/api/replication/v1/message.rb +1 -1
- data/lib/temporalio/api/rules/v1/message.rb +27 -0
- data/lib/temporalio/api/schedule/v1/message.rb +2 -2
- data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +1 -1
- data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +1 -1
- data/lib/temporalio/api/sdk/v1/user_metadata.rb +1 -1
- data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +1 -1
- data/lib/temporalio/api/taskqueue/v1/message.rb +5 -2
- data/lib/temporalio/api/testservice/v1/request_response.rb +1 -1
- data/lib/temporalio/api/testservice/v1/service.rb +1 -1
- data/lib/temporalio/api/update/v1/message.rb +1 -1
- data/lib/temporalio/api/version/v1/message.rb +1 -1
- data/lib/temporalio/api/worker/v1/message.rb +30 -0
- data/lib/temporalio/api/workflow/v1/message.rb +22 -2
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +58 -12
- data/lib/temporalio/api/workflowservice/v1/service.rb +2 -2
- data/lib/temporalio/api.rb +1 -0
- data/lib/temporalio/client/async_activity_handle.rb +12 -4
- data/lib/temporalio/client/connection/cloud_service.rb +60 -0
- data/lib/temporalio/client/connection/workflow_service.rb +343 -28
- data/lib/temporalio/client/interceptor.rb +64 -7
- data/lib/temporalio/client/schedule.rb +35 -3
- data/lib/temporalio/client/with_start_workflow_operation.rb +123 -0
- data/lib/temporalio/client/workflow_execution.rb +19 -0
- data/lib/temporalio/client/workflow_handle.rb +47 -7
- data/lib/temporalio/client/workflow_update_handle.rb +9 -3
- data/lib/temporalio/client.rb +231 -4
- data/lib/temporalio/common_enums.rb +14 -0
- data/lib/temporalio/contrib/open_telemetry.rb +474 -0
- data/lib/temporalio/converters/data_converter.rb +18 -8
- data/lib/temporalio/converters/failure_converter.rb +6 -3
- data/lib/temporalio/converters/payload_converter/binary_null.rb +2 -2
- data/lib/temporalio/converters/payload_converter/binary_plain.rb +2 -2
- data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +2 -2
- data/lib/temporalio/converters/payload_converter/composite.rb +6 -4
- data/lib/temporalio/converters/payload_converter/encoding.rb +4 -2
- data/lib/temporalio/converters/payload_converter/json_plain.rb +2 -2
- data/lib/temporalio/converters/payload_converter/json_protobuf.rb +2 -2
- data/lib/temporalio/converters/payload_converter.rb +16 -6
- data/lib/temporalio/error/failure.rb +19 -1
- data/lib/temporalio/error.rb +2 -1
- data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +1 -1
- data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +3 -2
- data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +1 -1
- data/lib/temporalio/internal/bridge/api/common/common.rb +3 -2
- data/lib/temporalio/internal/bridge/api/core_interface.rb +1 -1
- data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +1 -1
- data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +3 -2
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +2 -2
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +3 -2
- data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +3 -2
- data/lib/temporalio/internal/bridge/runtime.rb +3 -0
- data/lib/temporalio/internal/bridge/testing.rb +3 -0
- data/lib/temporalio/internal/bridge/worker.rb +28 -4
- data/lib/temporalio/internal/bridge.rb +1 -1
- data/lib/temporalio/internal/client/implementation.rb +281 -51
- data/lib/temporalio/internal/proto_utils.rb +38 -6
- data/lib/temporalio/internal/worker/activity_worker.rb +112 -27
- data/lib/temporalio/internal/worker/multi_runner.rb +2 -2
- data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +8 -6
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +100 -5
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +7 -2
- data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +2 -2
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +64 -18
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +39 -40
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +22 -2
- data/lib/temporalio/internal/worker/workflow_instance.rb +134 -55
- data/lib/temporalio/internal/worker/workflow_worker.rb +74 -21
- data/lib/temporalio/priority.rb +59 -0
- data/lib/temporalio/runtime/metric_buffer.rb +94 -0
- data/lib/temporalio/runtime.rb +48 -10
- data/lib/temporalio/search_attributes.rb +13 -0
- data/lib/temporalio/testing/activity_environment.rb +59 -16
- data/lib/temporalio/testing/workflow_environment.rb +29 -6
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/versioning_override.rb +56 -0
- data/lib/temporalio/worker/deployment_options.rb +45 -0
- data/lib/temporalio/worker/illegal_workflow_call_validator.rb +64 -0
- data/lib/temporalio/worker/interceptor.rb +16 -1
- data/lib/temporalio/worker/poller_behavior.rb +61 -0
- data/lib/temporalio/worker/thread_pool.rb +6 -6
- data/lib/temporalio/worker/tuner.rb +38 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +14 -8
- data/lib/temporalio/worker/workflow_executor.rb +1 -1
- data/lib/temporalio/worker/workflow_replayer.rb +349 -0
- data/lib/temporalio/worker.rb +117 -75
- data/lib/temporalio/worker_deployment_version.rb +67 -0
- data/lib/temporalio/workflow/child_workflow_handle.rb +10 -2
- data/lib/temporalio/workflow/definition.rb +217 -35
- data/lib/temporalio/workflow/external_workflow_handle.rb +3 -1
- data/lib/temporalio/workflow/future.rb +2 -2
- data/lib/temporalio/workflow/info.rb +26 -1
- data/lib/temporalio/workflow.rb +119 -15
- data/lib/temporalio/workflow_history.rb +26 -1
- data/lib/temporalio.rb +1 -0
- data/temporalio.gemspec +3 -1
- metadata +34 -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
         | 
| @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'temporalio/internal/bridge/worker'
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module Temporalio
         | 
| 4 6 | 
             
              class Worker
         | 
| 5 7 | 
             
                # Worker tuner that allows for dynamic customization of some aspects of worker configuration.
         | 
| @@ -18,6 +20,14 @@ module Temporalio | |
| 18 20 | 
             
                      def initialize(slots) # rubocop:disable Lint/MissingSuper
         | 
| 19 21 | 
             
                        @slots = slots
         | 
| 20 22 | 
             
                      end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                      # @!visibility private
         | 
| 25 | 
            +
                      def _to_bridge_options
         | 
| 26 | 
            +
                        Internal::Bridge::Worker::TunerSlotSupplierOptions.new(
         | 
| 27 | 
            +
                          fixed_size: slots,
         | 
| 28 | 
            +
                          resource_based: nil
         | 
| 29 | 
            +
                        )
         | 
| 30 | 
            +
                      end
         | 
| 21 31 | 
             
                    end
         | 
| 22 32 |  | 
| 23 33 | 
             
                    # A slot supplier that will dynamically adjust the number of slots based on resource usage.
         | 
| @@ -34,6 +44,25 @@ module Temporalio | |
| 34 44 | 
             
                        @tuner_options = tuner_options
         | 
| 35 45 | 
             
                        @slot_options = slot_options
         | 
| 36 46 | 
             
                      end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                      # @!visibility private
         | 
| 49 | 
            +
                      def _to_bridge_options
         | 
| 50 | 
            +
                        Internal::Bridge::Worker::TunerSlotSupplierOptions.new(
         | 
| 51 | 
            +
                          fixed_size: nil,
         | 
| 52 | 
            +
                          resource_based: Internal::Bridge::Worker::TunerResourceBasedSlotSupplierOptions.new(
         | 
| 53 | 
            +
                            target_mem_usage: tuner_options.target_memory_usage,
         | 
| 54 | 
            +
                            target_cpu_usage: tuner_options.target_cpu_usage,
         | 
| 55 | 
            +
                            min_slots: slot_options.min_slots,
         | 
| 56 | 
            +
                            max_slots: slot_options.max_slots,
         | 
| 57 | 
            +
                            ramp_throttle: slot_options.ramp_throttle
         | 
| 58 | 
            +
                          )
         | 
| 59 | 
            +
                        )
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    # @!visibility private
         | 
| 64 | 
            +
                    def _to_bridge_options
         | 
| 65 | 
            +
                      raise ArgumentError, 'Tuner slot suppliers must be instances of Fixed or ResourceBased'
         | 
| 37 66 | 
             
                    end
         | 
| 38 67 | 
             
                  end
         | 
| 39 68 |  | 
| @@ -146,6 +175,15 @@ module Temporalio | |
| 146 175 | 
             
                    @activity_slot_supplier = activity_slot_supplier
         | 
| 147 176 | 
             
                    @local_activity_slot_supplier = local_activity_slot_supplier
         | 
| 148 177 | 
             
                  end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                  # @!visibility private
         | 
| 180 | 
            +
                  def _to_bridge_options
         | 
| 181 | 
            +
                    Internal::Bridge::Worker::TunerOptions.new(
         | 
| 182 | 
            +
                      workflow_slot_supplier: workflow_slot_supplier._to_bridge_options,
         | 
| 183 | 
            +
                      activity_slot_supplier: activity_slot_supplier._to_bridge_options,
         | 
| 184 | 
            +
                      local_activity_slot_supplier: local_activity_slot_supplier._to_bridge_options
         | 
| 185 | 
            +
                    )
         | 
| 186 | 
            +
                  end
         | 
| 149 187 | 
             
                end
         | 
| 150 188 | 
             
              end
         | 
| 151 189 | 
             
            end
         | 
| @@ -36,7 +36,7 @@ module Temporalio | |
| 36 36 | 
             
                    end
         | 
| 37 37 |  | 
| 38 38 | 
             
                    # @!visibility private
         | 
| 39 | 
            -
                    def _validate_worker( | 
| 39 | 
            +
                    def _validate_worker(workflow_worker, worker_state)
         | 
| 40 40 | 
             
                      # Do nothing
         | 
| 41 41 | 
             
                    end
         | 
| 42 42 |  | 
| @@ -137,7 +137,7 @@ module Temporalio | |
| 137 137 |  | 
| 138 138 | 
             
                        # If it's eviction only, just evict inline and do nothing else
         | 
| 139 139 | 
             
                        if cache_remove_job && activation.jobs.size == 1
         | 
| 140 | 
            -
                          evict(worker_state, activation.run_id)
         | 
| 140 | 
            +
                          evict(worker_state, activation.run_id, cache_remove_job)
         | 
| 141 141 | 
             
                          worker_state.logger.debug('Sending empty workflow completion') if LOG_ACTIVATIONS
         | 
| 142 142 | 
             
                          yield Internal::Bridge::Api::WorkflowCompletion::WorkflowActivationCompletion.new(
         | 
| 143 143 | 
             
                            run_id: activation.run_id,
         | 
| @@ -173,7 +173,7 @@ module Temporalio | |
| 173 173 | 
             
                        end
         | 
| 174 174 |  | 
| 175 175 | 
             
                        # Go ahead and evict if there is an eviction job
         | 
| 176 | 
            -
                        evict(worker_state, activation.run_id) if cache_remove_job
         | 
| 176 | 
            +
                        evict(worker_state, activation.run_id, cache_remove_job) if cache_remove_job
         | 
| 177 177 |  | 
| 178 178 | 
             
                        # Complete the activation
         | 
| 179 179 | 
             
                        worker_state.logger.debug("Sending workflow completion: #{completion}") if LOG_ACTIVATIONS
         | 
| @@ -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 | 
            -
             | 
| 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,13 +213,15 @@ 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
         | 
| 216 222 |  | 
| 217 | 
            -
                      def evict(worker_state, run_id)
         | 
| 218 | 
            -
                        worker_state.evict_running_workflow(run_id)
         | 
| 223 | 
            +
                      def evict(worker_state, run_id, cache_remove_job)
         | 
| 224 | 
            +
                        worker_state.evict_running_workflow(run_id, cache_remove_job)
         | 
| 219 225 | 
             
                        @executor._remove_workflow(worker_state, run_id)
         | 
| 220 226 | 
             
                      end
         | 
| 221 227 | 
             
                    end
         | 
| @@ -0,0 +1,349 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'temporalio/api'
         | 
| 4 | 
            +
            require 'temporalio/converters'
         | 
| 5 | 
            +
            require 'temporalio/internal/bridge'
         | 
| 6 | 
            +
            require 'temporalio/internal/bridge/worker'
         | 
| 7 | 
            +
            require 'temporalio/internal/worker/multi_runner'
         | 
| 8 | 
            +
            require 'temporalio/internal/worker/workflow_worker'
         | 
| 9 | 
            +
            require 'temporalio/worker/interceptor'
         | 
| 10 | 
            +
            require 'temporalio/worker/poller_behavior'
         | 
| 11 | 
            +
            require 'temporalio/worker/thread_pool'
         | 
| 12 | 
            +
            require 'temporalio/worker/tuner'
         | 
| 13 | 
            +
            require 'temporalio/worker/workflow_executor'
         | 
| 14 | 
            +
            require 'temporalio/workflow'
         | 
| 15 | 
            +
            require 'temporalio/workflow_history'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            module Temporalio
         | 
| 18 | 
            +
              class Worker
         | 
| 19 | 
            +
                # Replayer to replay workflows from existing history.
         | 
| 20 | 
            +
                class WorkflowReplayer
         | 
| 21 | 
            +
                  Options = Data.define(
         | 
| 22 | 
            +
                    :workflows,
         | 
| 23 | 
            +
                    :namespace,
         | 
| 24 | 
            +
                    :task_queue,
         | 
| 25 | 
            +
                    :data_converter,
         | 
| 26 | 
            +
                    :workflow_executor,
         | 
| 27 | 
            +
                    :interceptors,
         | 
| 28 | 
            +
                    :identity,
         | 
| 29 | 
            +
                    :logger,
         | 
| 30 | 
            +
                    :illegal_workflow_calls,
         | 
| 31 | 
            +
                    :workflow_failure_exception_types,
         | 
| 32 | 
            +
                    :workflow_payload_codec_thread_pool,
         | 
| 33 | 
            +
                    :unsafe_workflow_io_enabled,
         | 
| 34 | 
            +
                    :debug_mode,
         | 
| 35 | 
            +
                    :runtime
         | 
| 36 | 
            +
                  )
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  # Options as returned from {options} representing the options passed to the constructor.
         | 
| 39 | 
            +
                  class Options; end # rubocop:disable Lint/EmptyClass
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  # @return [Options] Options for this replayer which has the same attributes as {initialize}.
         | 
| 42 | 
            +
                  attr_reader :options
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  # Create a new replayer. This combines some options from both {Worker.initialize} and {Client.initialize}.
         | 
| 45 | 
            +
                  #
         | 
| 46 | 
            +
                  # @param workflows [Array<Class<Workflow::Definition>>] Workflows for this replayer.
         | 
| 47 | 
            +
                  # @param namespace [String] Namespace as set in the workflow info.
         | 
| 48 | 
            +
                  # @param task_queue [String] Task queue as set in the workflow info.
         | 
| 49 | 
            +
                  # @param data_converter [Converters::DataConverter] Data converter to use for all data conversions to/from
         | 
| 50 | 
            +
                  #   payloads.
         | 
| 51 | 
            +
                  # @param workflow_executor [WorkflowExecutor] Workflow executor that workflow tasks run within. This must be a
         | 
| 52 | 
            +
                  #   {WorkflowExecutor::ThreadPool} currently.
         | 
| 53 | 
            +
                  # @param interceptors [Array<Interceptor::Workflow>] Workflow interceptors.
         | 
| 54 | 
            +
                  # @param identity [String, nil] Override the identity for this replater.
         | 
| 55 | 
            +
                  # @param logger [Logger] Logger to use. Defaults to stdout with warn level. Callers setting this logger are
         | 
| 56 | 
            +
                  #   responsible for closing it.
         | 
| 57 | 
            +
                  # @param illegal_workflow_calls [Hash<String, [:all, Array<Symbol>]>] Set of illegal workflow calls that are
         | 
| 58 | 
            +
                  #   considered unsafe/non-deterministic and will raise if seen. The key of the hash is the fully qualified string
         | 
| 59 | 
            +
                  #   class name (no leading `::`). The value is either `:all` which means any use of the class, or an array of
         | 
| 60 | 
            +
                  #   symbols for methods on the class that cannot be used. The methods refer to either instance or class methods,
         | 
| 61 | 
            +
                  #   there is no way to differentiate at this time.
         | 
| 62 | 
            +
                  # @param workflow_failure_exception_types [Array<Class<Exception>>] Workflow failure exception types. This is the
         | 
| 63 | 
            +
                  #   set of exception types that, if a workflow-thrown exception extends, will cause the workflow/update to fail
         | 
| 64 | 
            +
                  #   instead of suspending the workflow via task failure. These are applied in addition to the
         | 
| 65 | 
            +
                  #   `workflow_failure_exception_type` on the workflow definition class itself. If {::Exception} is set, it
         | 
| 66 | 
            +
                  #   effectively will fail a workflow/update in all user exception cases.
         | 
| 67 | 
            +
                  # @param workflow_payload_codec_thread_pool [ThreadPool, nil] Thread pool to run payload codec encode/decode
         | 
| 68 | 
            +
                  #   within. This is required if a payload codec exists and the worker is not fiber based. Codecs can potentially
         | 
| 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.
         | 
| 73 | 
            +
                  # @param debug_mode [Boolean] If true, deadlock detection is disabled. Deadlock detection will fail workflow tasks
         | 
| 74 | 
            +
                  #   if they block the thread for too long. This defaults to true if the `TEMPORAL_DEBUG` environment variable is
         | 
| 75 | 
            +
                  #   `true` or `1`.
         | 
| 76 | 
            +
                  # @param runtime [Runtime] Runtime for this replayer.
         | 
| 77 | 
            +
                  #
         | 
| 78 | 
            +
                  # @yield If a block is present, this is the equivalent of calling {with_replay_worker} with the block and
         | 
| 79 | 
            +
                  #   discarding the result.
         | 
| 80 | 
            +
                  def initialize(
         | 
| 81 | 
            +
                    workflows:,
         | 
| 82 | 
            +
                    namespace: 'ReplayNamespace',
         | 
| 83 | 
            +
                    task_queue: 'ReplayTaskQueue',
         | 
| 84 | 
            +
                    data_converter: Converters::DataConverter.default,
         | 
| 85 | 
            +
                    workflow_executor: WorkflowExecutor::ThreadPool.default,
         | 
| 86 | 
            +
                    interceptors: [],
         | 
| 87 | 
            +
                    identity: nil,
         | 
| 88 | 
            +
                    logger: Logger.new($stdout, level: Logger::WARN),
         | 
| 89 | 
            +
                    illegal_workflow_calls: Worker.default_illegal_workflow_calls,
         | 
| 90 | 
            +
                    workflow_failure_exception_types: [],
         | 
| 91 | 
            +
                    workflow_payload_codec_thread_pool: nil,
         | 
| 92 | 
            +
                    unsafe_workflow_io_enabled: false,
         | 
| 93 | 
            +
                    debug_mode: %w[true 1].include?(ENV['TEMPORAL_DEBUG'].to_s.downcase),
         | 
| 94 | 
            +
                    runtime: Runtime.default,
         | 
| 95 | 
            +
                    &
         | 
| 96 | 
            +
                  )
         | 
| 97 | 
            +
                    @options = Options.new(
         | 
| 98 | 
            +
                      workflows:,
         | 
| 99 | 
            +
                      namespace:,
         | 
| 100 | 
            +
                      task_queue:,
         | 
| 101 | 
            +
                      data_converter:,
         | 
| 102 | 
            +
                      workflow_executor:,
         | 
| 103 | 
            +
                      interceptors:,
         | 
| 104 | 
            +
                      identity:,
         | 
| 105 | 
            +
                      logger:,
         | 
| 106 | 
            +
                      illegal_workflow_calls:,
         | 
| 107 | 
            +
                      workflow_failure_exception_types:,
         | 
| 108 | 
            +
                      workflow_payload_codec_thread_pool:,
         | 
| 109 | 
            +
                      unsafe_workflow_io_enabled:,
         | 
| 110 | 
            +
                      debug_mode:,
         | 
| 111 | 
            +
                      runtime:
         | 
| 112 | 
            +
                    ).freeze
         | 
| 113 | 
            +
                    # Preload definitions and other settings
         | 
| 114 | 
            +
                    @workflow_definitions = Internal::Worker::WorkflowWorker.workflow_definitions(
         | 
| 115 | 
            +
                      workflows, should_enforce_versioning_behavior: false
         | 
| 116 | 
            +
                    )
         | 
| 117 | 
            +
                    @nondeterminism_as_workflow_fail, @nondeterminism_as_workflow_fail_for_types =
         | 
| 118 | 
            +
                      Internal::Worker::WorkflowWorker.bridge_workflow_failure_exception_type_options(
         | 
| 119 | 
            +
                        workflow_failure_exception_types:, workflow_definitions: @workflow_definitions
         | 
| 120 | 
            +
                      )
         | 
| 121 | 
            +
                    # If there is a block, we'll go ahead and assume it's for with_replay_worker
         | 
| 122 | 
            +
                    with_replay_worker(&) if block_given? # steep:ignore
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  # Replay a workflow history.
         | 
| 126 | 
            +
                  #
         | 
| 127 | 
            +
                  # If doing multiple histories, it is better to use {replay_workflows} or {with_replay_worker} since they create
         | 
| 128 | 
            +
                  # a replay worker just once instead of each time like this call does.
         | 
| 129 | 
            +
                  #
         | 
| 130 | 
            +
                  # @param history [WorkflowHistory] History to replay.
         | 
| 131 | 
            +
                  # @param raise_on_replay_failure [Boolean] If true, the default, this will raise an exception on any replay
         | 
| 132 | 
            +
                  #   failure. If false and the replay fails, the failure will be available in {ReplayResult.replay_failure}.
         | 
| 133 | 
            +
                  #
         | 
| 134 | 
            +
                  # @return [ReplayResult] Result of the replay.
         | 
| 135 | 
            +
                  def replay_workflow(history, raise_on_replay_failure: true)
         | 
| 136 | 
            +
                    with_replay_worker { |worker| worker.replay_workflow(history, raise_on_replay_failure:) }
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  # Replay multiple workflow histories.
         | 
| 140 | 
            +
                  #
         | 
| 141 | 
            +
                  # @param histories [Enumerable<WorkflowHistory>] Histories to replay.
         | 
| 142 | 
            +
                  # @param raise_on_replay_failure [Boolean] If true, this will raise an exception on any replay failure. If false,
         | 
| 143 | 
            +
                  #   the default, and the replay fails, the failure will be available in {ReplayResult.replay_failure}.
         | 
| 144 | 
            +
                  #
         | 
| 145 | 
            +
                  # @return [Array<ReplayResult>] Results of the replay.
         | 
| 146 | 
            +
                  def replay_workflows(histories, raise_on_replay_failure: false)
         | 
| 147 | 
            +
                    with_replay_worker do |worker|
         | 
| 148 | 
            +
                      histories.map { |h| worker.replay_workflow(h, raise_on_replay_failure:) }
         | 
| 149 | 
            +
                    end
         | 
| 150 | 
            +
                  end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                  # Run a block of code with a {ReplayWorker} to execute replays.
         | 
| 153 | 
            +
                  #
         | 
| 154 | 
            +
                  # @yield Block of code to run with a replay worker.
         | 
| 155 | 
            +
                  # @yieldparam [ReplayWorker] Worker to run replays on. Note, only one workflow can replay at a time.
         | 
| 156 | 
            +
                  # @yieldreturn [Object] Result of the block.
         | 
| 157 | 
            +
                  def with_replay_worker(&)
         | 
| 158 | 
            +
                    worker = ReplayWorker.new(
         | 
| 159 | 
            +
                      options:,
         | 
| 160 | 
            +
                      workflow_definitions: @workflow_definitions,
         | 
| 161 | 
            +
                      nondeterminism_as_workflow_fail: @nondeterminism_as_workflow_fail,
         | 
| 162 | 
            +
                      nondeterminism_as_workflow_fail_for_types: @nondeterminism_as_workflow_fail_for_types
         | 
| 163 | 
            +
                    )
         | 
| 164 | 
            +
                    begin
         | 
| 165 | 
            +
                      yield worker
         | 
| 166 | 
            +
                    ensure
         | 
| 167 | 
            +
                      worker._shutdown
         | 
| 168 | 
            +
                    end
         | 
| 169 | 
            +
                  end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                  # Result of a single workflow replay run.
         | 
| 172 | 
            +
                  class ReplayResult
         | 
| 173 | 
            +
                    # @return [WorkflowHistory] History originally passed in to the replayer.
         | 
| 174 | 
            +
                    attr_reader :history
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                    # @return [Exception, nil] Failure during replay if any.
         | 
| 177 | 
            +
                    attr_reader :replay_failure
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                    # @!visibility private
         | 
| 180 | 
            +
                    def initialize(history:, replay_failure:)
         | 
| 181 | 
            +
                      @history = history
         | 
| 182 | 
            +
                      @replay_failure = replay_failure
         | 
| 183 | 
            +
                    end
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                  # Replay worker that can be used to replay individual workflow runs. Only one call to {replay_workflow} can be
         | 
| 187 | 
            +
                  # made at a time.
         | 
| 188 | 
            +
                  class ReplayWorker
         | 
| 189 | 
            +
                    # @!visibility private
         | 
| 190 | 
            +
                    def initialize(
         | 
| 191 | 
            +
                      options:,
         | 
| 192 | 
            +
                      workflow_definitions:,
         | 
| 193 | 
            +
                      nondeterminism_as_workflow_fail:,
         | 
| 194 | 
            +
                      nondeterminism_as_workflow_fail_for_types:
         | 
| 195 | 
            +
                    )
         | 
| 196 | 
            +
                      # Create the bridge worker and the replayer
         | 
| 197 | 
            +
                      @bridge_replayer, @bridge_worker = Internal::Bridge::Worker::WorkflowReplayer.new(
         | 
| 198 | 
            +
                        options.runtime._core_runtime,
         | 
| 199 | 
            +
                        Internal::Bridge::Worker::Options.new(
         | 
| 200 | 
            +
                          activity: false,
         | 
| 201 | 
            +
                          workflow: true,
         | 
| 202 | 
            +
                          namespace: options.namespace,
         | 
| 203 | 
            +
                          task_queue: options.task_queue,
         | 
| 204 | 
            +
                          tuner: Tuner.create_fixed(
         | 
| 205 | 
            +
                            workflow_slots: 2, activity_slots: 1, local_activity_slots: 1
         | 
| 206 | 
            +
                          )._to_bridge_options,
         | 
| 207 | 
            +
                          identity_override: options.identity,
         | 
| 208 | 
            +
                          max_cached_workflows: 2,
         | 
| 209 | 
            +
                          workflow_task_poller_behavior:
         | 
| 210 | 
            +
                            Temporalio::Worker::PollerBehavior::SimpleMaximum.new(2)._to_bridge_options,
         | 
| 211 | 
            +
                          nonsticky_to_sticky_poll_ratio: 1.0,
         | 
| 212 | 
            +
                          activity_task_poller_behavior:
         | 
| 213 | 
            +
                            Temporalio::Worker::PollerBehavior::SimpleMaximum.new(1)._to_bridge_options,
         | 
| 214 | 
            +
                          no_remote_activities: true,
         | 
| 215 | 
            +
                          sticky_queue_schedule_to_start_timeout: 1.0,
         | 
| 216 | 
            +
                          max_heartbeat_throttle_interval: 1.0,
         | 
| 217 | 
            +
                          default_heartbeat_throttle_interval: 1.0,
         | 
| 218 | 
            +
                          max_worker_activities_per_second: nil,
         | 
| 219 | 
            +
                          max_task_queue_activities_per_second: nil,
         | 
| 220 | 
            +
                          graceful_shutdown_period: 0.0,
         | 
| 221 | 
            +
                          nondeterminism_as_workflow_fail:,
         | 
| 222 | 
            +
                          nondeterminism_as_workflow_fail_for_types:,
         | 
| 223 | 
            +
                          deployment_options: Worker.default_deployment_options._to_bridge_options
         | 
| 224 | 
            +
                        )
         | 
| 225 | 
            +
                      )
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                      # Create the workflow worker
         | 
| 228 | 
            +
                      @workflow_worker = Internal::Worker::WorkflowWorker.new(
         | 
| 229 | 
            +
                        bridge_worker: @bridge_worker,
         | 
| 230 | 
            +
                        namespace: options.namespace,
         | 
| 231 | 
            +
                        task_queue: options.task_queue,
         | 
| 232 | 
            +
                        workflow_definitions:,
         | 
| 233 | 
            +
                        workflow_executor: options.workflow_executor,
         | 
| 234 | 
            +
                        logger: options.logger,
         | 
| 235 | 
            +
                        data_converter: options.data_converter,
         | 
| 236 | 
            +
                        metric_meter: options.runtime.metric_meter,
         | 
| 237 | 
            +
                        workflow_interceptors: options.interceptors.select do |i|
         | 
| 238 | 
            +
                          i.is_a?(Interceptor::Workflow)
         | 
| 239 | 
            +
                        end,
         | 
| 240 | 
            +
                        disable_eager_activity_execution: false,
         | 
| 241 | 
            +
                        illegal_workflow_calls: options.illegal_workflow_calls,
         | 
| 242 | 
            +
                        workflow_failure_exception_types: options.workflow_failure_exception_types,
         | 
| 243 | 
            +
                        workflow_payload_codec_thread_pool: options.workflow_payload_codec_thread_pool,
         | 
| 244 | 
            +
                        unsafe_workflow_io_enabled: options.unsafe_workflow_io_enabled,
         | 
| 245 | 
            +
                        debug_mode: options.debug_mode,
         | 
| 246 | 
            +
                        on_eviction: proc { |_, remove_job| @last_workflow_remove_job = remove_job }, # steep:ignore
         | 
| 247 | 
            +
                        assert_valid_local_activity: ->(_) {}
         | 
| 248 | 
            +
                      )
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                      # Create the runner
         | 
| 251 | 
            +
                      @runner = Internal::Worker::MultiRunner.new(workers: [self], shutdown_signals: [])
         | 
| 252 | 
            +
                    end
         | 
| 253 | 
            +
             | 
| 254 | 
            +
                    # Replay a workflow history.
         | 
| 255 | 
            +
                    #
         | 
| 256 | 
            +
                    # @param history [WorkflowHistory] History to replay.
         | 
| 257 | 
            +
                    # @param raise_on_replay_failure [Boolean] If true, the default, this will raise an exception on any replay
         | 
| 258 | 
            +
                    #   failure. If false and the replay fails, the failure will be available in {ReplayResult.replay_failure}.
         | 
| 259 | 
            +
                    #
         | 
| 260 | 
            +
                    # @return [ReplayResult] Result of the replay.
         | 
| 261 | 
            +
                    def replay_workflow(history, raise_on_replay_failure: true)
         | 
| 262 | 
            +
                      raise ArgumentError, 'Expected history as WorkflowHistory' unless history.is_a?(WorkflowHistory)
         | 
| 263 | 
            +
                      # Due to our event processing model, only one can run at a time
         | 
| 264 | 
            +
                      raise 'Already running' if @running
         | 
| 265 | 
            +
                      raise 'Replayer shutdown' if @shutdown
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                      # Push history proto
         | 
| 268 | 
            +
                      # TODO(cretz): Unset this
         | 
| 269 | 
            +
                      @running = true
         | 
| 270 | 
            +
                      @last_workflow_remove_job = nil
         | 
| 271 | 
            +
                      begin
         | 
| 272 | 
            +
                        @bridge_replayer.push_history(
         | 
| 273 | 
            +
                          history.workflow_id, Api::History::V1::History.new(events: history.events).to_proto
         | 
| 274 | 
            +
                        )
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                        # Process events until workflow complete
         | 
| 277 | 
            +
                        until @last_workflow_remove_job
         | 
| 278 | 
            +
                          event = @runner.next_event
         | 
| 279 | 
            +
                          case event
         | 
| 280 | 
            +
                          when Internal::Worker::MultiRunner::Event::PollSuccess
         | 
| 281 | 
            +
                            @workflow_worker.handle_activation(
         | 
| 282 | 
            +
                              runner: @runner,
         | 
| 283 | 
            +
                              activation: Internal::Bridge::Api::WorkflowActivation::WorkflowActivation.decode(event.bytes),
         | 
| 284 | 
            +
                              decoded: false
         | 
| 285 | 
            +
                            )
         | 
| 286 | 
            +
                          when Internal::Worker::MultiRunner::Event::WorkflowActivationDecoded
         | 
| 287 | 
            +
                            @workflow_worker.handle_activation(runner: @runner, activation: event.activation, decoded: true)
         | 
| 288 | 
            +
                          when Internal::Worker::MultiRunner::Event::WorkflowActivationComplete
         | 
| 289 | 
            +
                            @workflow_worker.handle_activation_complete(
         | 
| 290 | 
            +
                              runner: @runner,
         | 
| 291 | 
            +
                              activation_completion: event.activation_completion,
         | 
| 292 | 
            +
                              encoded: event.encoded,
         | 
| 293 | 
            +
                              completion_complete_queue: event.completion_complete_queue
         | 
| 294 | 
            +
                            )
         | 
| 295 | 
            +
                          when Internal::Worker::MultiRunner::Event::WorkflowActivationCompletionComplete
         | 
| 296 | 
            +
                          # Ignore
         | 
| 297 | 
            +
                          else
         | 
| 298 | 
            +
                            raise "Unexpected event: #{event}"
         | 
| 299 | 
            +
                          end
         | 
| 300 | 
            +
                        end
         | 
| 301 | 
            +
             | 
| 302 | 
            +
                        # Create exception if removal is due to error
         | 
| 303 | 
            +
                        err = if @last_workflow_remove_job.reason == :NONDETERMINISM
         | 
| 304 | 
            +
                                Workflow::NondeterminismError.new(
         | 
| 305 | 
            +
                                  "#{@last_workflow_remove_job.reason}: #{@last_workflow_remove_job.message}"
         | 
| 306 | 
            +
                                )
         | 
| 307 | 
            +
                              elsif !%i[CACHE_FULL LANG_REQUESTED].include?(@last_workflow_remove_job.reason)
         | 
| 308 | 
            +
                                Workflow::InvalidWorkflowStateError.new(
         | 
| 309 | 
            +
                                  "#{@last_workflow_remove_job.reason}: #{@last_workflow_remove_job.message}"
         | 
| 310 | 
            +
                                )
         | 
| 311 | 
            +
                              end
         | 
| 312 | 
            +
                        # Raise if wanting to raise, otherwise return result
         | 
| 313 | 
            +
                        raise err if raise_on_replay_failure && err
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                        ReplayResult.new(history:, replay_failure: err)
         | 
| 316 | 
            +
                      ensure
         | 
| 317 | 
            +
                        @running = false
         | 
| 318 | 
            +
                      end
         | 
| 319 | 
            +
                    end
         | 
| 320 | 
            +
             | 
| 321 | 
            +
                    # @!visibility private
         | 
| 322 | 
            +
                    def _shutdown
         | 
| 323 | 
            +
                      @shutdown = true
         | 
| 324 | 
            +
                      @runner.initiate_shutdown
         | 
| 325 | 
            +
                      # Wait for all-pollers-shutdown before finalizing
         | 
| 326 | 
            +
                      until @runner.next_event.is_a?(Internal::Worker::MultiRunner::Event::AllPollersShutDown); end
         | 
| 327 | 
            +
                      @runner.wait_complete_and_finalize_shutdown
         | 
| 328 | 
            +
                      @workflow_worker.on_shutdown_complete
         | 
| 329 | 
            +
                      @workflow_worker = nil
         | 
| 330 | 
            +
                    end
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                    # @!visibility private
         | 
| 333 | 
            +
                    def _bridge_worker
         | 
| 334 | 
            +
                      @bridge_worker
         | 
| 335 | 
            +
                    end
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                    # @!visibility private
         | 
| 338 | 
            +
                    def _initiate_shutdown
         | 
| 339 | 
            +
                      _bridge_worker.initiate_shutdown
         | 
| 340 | 
            +
                    end
         | 
| 341 | 
            +
             | 
| 342 | 
            +
                    # @!visibility private
         | 
| 343 | 
            +
                    def _wait_all_complete
         | 
| 344 | 
            +
                      # Do nothing
         | 
| 345 | 
            +
                    end
         | 
| 346 | 
            +
                  end
         | 
| 347 | 
            +
                end
         | 
| 348 | 
            +
              end
         | 
| 349 | 
            +
            end
         |