temporalio 0.3.0-x86_64-darwin → 0.4.0-x86_64-darwin
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/Gemfile +4 -0
- data/Rakefile +1 -1
- data/lib/temporalio/activity/context.rb +13 -0
- data/lib/temporalio/activity/definition.rb +22 -5
- data/lib/temporalio/activity/info.rb +3 -0
- data/lib/temporalio/api/batch/v1/message.rb +6 -1
- data/lib/temporalio/api/command/v1/message.rb +1 -1
- data/lib/temporalio/api/common/v1/message.rb +2 -1
- data/lib/temporalio/api/deployment/v1/message.rb +38 -0
- data/lib/temporalio/api/enums/v1/batch_operation.rb +1 -1
- data/lib/temporalio/api/enums/v1/common.rb +1 -1
- data/lib/temporalio/api/enums/v1/deployment.rb +23 -0
- data/lib/temporalio/api/enums/v1/event_type.rb +1 -1
- data/lib/temporalio/api/enums/v1/failed_cause.rb +1 -1
- data/lib/temporalio/api/enums/v1/nexus.rb +21 -0
- data/lib/temporalio/api/enums/v1/reset.rb +1 -1
- data/lib/temporalio/api/enums/v1/workflow.rb +2 -1
- data/lib/temporalio/api/errordetails/v1/message.rb +3 -1
- data/lib/temporalio/api/failure/v1/message.rb +3 -1
- data/lib/temporalio/api/history/v1/message.rb +3 -1
- data/lib/temporalio/api/nexus/v1/message.rb +2 -1
- data/lib/temporalio/api/payload_visitor.rb +75 -7
- data/lib/temporalio/api/query/v1/message.rb +2 -1
- data/lib/temporalio/api/taskqueue/v1/message.rb +4 -1
- data/lib/temporalio/api/workflow/v1/message.rb +9 -1
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +40 -11
- data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
- data/lib/temporalio/api.rb +1 -0
- data/lib/temporalio/client/connection/workflow_service.rb +238 -28
- data/lib/temporalio/client/interceptor.rb +39 -0
- data/lib/temporalio/client/schedule.rb +25 -1
- data/lib/temporalio/client/with_start_workflow_operation.rb +115 -0
- data/lib/temporalio/client/workflow_execution.rb +19 -0
- data/lib/temporalio/client/workflow_handle.rb +3 -3
- data/lib/temporalio/client.rb +125 -2
- data/lib/temporalio/contrib/open_telemetry.rb +470 -0
- data/lib/temporalio/error.rb +1 -0
- data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.bundle +0 -0
- data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.bundle +0 -0
- data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.bundle +0 -0
- data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +1 -1
- data/lib/temporalio/internal/bridge/api/common/common.rb +2 -1
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +1 -1
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +1 -1
- data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +2 -1
- data/lib/temporalio/internal/bridge/runtime.rb +3 -0
- data/lib/temporalio/internal/bridge/testing.rb +3 -0
- data/lib/temporalio/internal/client/implementation.rb +232 -10
- data/lib/temporalio/internal/proto_utils.rb +34 -2
- data/lib/temporalio/internal/worker/activity_worker.rb +20 -8
- data/lib/temporalio/internal/worker/multi_runner.rb +2 -2
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +57 -3
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +4 -2
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +11 -26
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +22 -2
- data/lib/temporalio/internal/worker/workflow_instance.rb +76 -32
- data/lib/temporalio/internal/worker/workflow_worker.rb +62 -19
- 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 +42 -14
- data/lib/temporalio/testing/workflow_environment.rb +26 -3
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/interceptor.rb +3 -0
- data/lib/temporalio/worker/thread_pool.rb +5 -5
- data/lib/temporalio/worker/tuner.rb +38 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +13 -8
- data/lib/temporalio/worker/workflow_executor.rb +1 -1
- data/lib/temporalio/worker/workflow_replayer.rb +350 -0
- data/lib/temporalio/worker.rb +58 -52
- data/lib/temporalio/workflow/definition.rb +40 -8
- data/lib/temporalio/workflow/future.rb +2 -2
- data/lib/temporalio/workflow/info.rb +22 -0
- data/lib/temporalio/workflow.rb +60 -8
- data/lib/temporalio/workflow_history.rb +26 -1
- data/temporalio.gemspec +2 -1
- metadata +25 -4
| @@ -93,8 +93,10 @@ module Temporalio | |
| 93 93 | 
             
                    def handle_start_task(task_token, start)
         | 
| 94 94 | 
             
                      set_running_activity(task_token, nil)
         | 
| 95 95 |  | 
| 96 | 
            -
                      # Find activity definition, falling back to dynamic if  | 
| 97 | 
            -
                      defn = @activities[start.activity_type] | 
| 96 | 
            +
                      # Find activity definition, falling back to dynamic if not found and not reserved name
         | 
| 97 | 
            +
                      defn = @activities[start.activity_type]
         | 
| 98 | 
            +
                      defn = @activities[nil] if !defn && !Internal::ProtoUtils.reserved_name?(start.activity_type)
         | 
| 99 | 
            +
             | 
| 98 100 | 
             
                      if defn.nil?
         | 
| 99 101 | 
             
                        raise Error::ApplicationError.new(
         | 
| 100 102 | 
             
                          "Activity #{start.activity_type} for workflow #{start.workflow_execution.workflow_id} " \
         | 
| @@ -114,7 +116,7 @@ module Temporalio | |
| 114 116 | 
             
                        # Unset at the end
         | 
| 115 117 | 
             
                        Activity::Context._current_executor = nil
         | 
| 116 118 | 
             
                      end
         | 
| 117 | 
            -
                    rescue Exception => e # rubocop:disable Lint/RescueException We are intending to catch everything here
         | 
| 119 | 
            +
                    rescue Exception => e # rubocop:disable Lint/RescueException -- We are intending to catch everything here
         | 
| 118 120 | 
             
                      remove_running_activity(task_token)
         | 
| 119 121 | 
             
                      @scoped_logger.warn("Failed starting activity #{start.activity_type}")
         | 
| 120 122 | 
             
                      @scoped_logger.warn(e)
         | 
| @@ -201,6 +203,7 @@ module Temporalio | |
| 201 203 |  | 
| 202 204 | 
             
                      # Run
         | 
| 203 205 | 
             
                      activity = RunningActivity.new(
         | 
| 206 | 
            +
                        worker: @worker,
         | 
| 204 207 | 
             
                        info:,
         | 
| 205 208 | 
             
                        cancellation: Cancellation.new,
         | 
| 206 209 | 
             
                        worker_shutdown_cancellation: @worker._worker_shutdown_cancellation,
         | 
| @@ -210,8 +213,8 @@ module Temporalio | |
| 210 213 | 
             
                      )
         | 
| 211 214 | 
             
                      Activity::Context._current_executor&.set_activity_context(defn, activity)
         | 
| 212 215 | 
             
                      set_running_activity(task_token, activity)
         | 
| 213 | 
            -
                      run_activity(activity, input)
         | 
| 214 | 
            -
                    rescue Exception => e # rubocop:disable Lint/RescueException We are intending to catch everything here
         | 
| 216 | 
            +
                      run_activity(defn, activity, input)
         | 
| 217 | 
            +
                    rescue Exception => e # rubocop:disable Lint/RescueException -- We are intending to catch everything here
         | 
| 215 218 | 
             
                      @scoped_logger.warn("Failed starting or sending completion for activity #{start.activity_type}")
         | 
| 216 219 | 
             
                      @scoped_logger.warn(e)
         | 
| 217 220 | 
             
                      # This means that the activity couldn't start or send completion (run
         | 
| @@ -236,8 +239,11 @@ module Temporalio | |
| 236 239 | 
             
                      remove_running_activity(task_token)
         | 
| 237 240 | 
             
                    end
         | 
| 238 241 |  | 
| 239 | 
            -
                    def run_activity(activity, input)
         | 
| 242 | 
            +
                    def run_activity(defn, activity, input)
         | 
| 240 243 | 
             
                      result = begin
         | 
| 244 | 
            +
                        # Create the instance. We choose to do this before interceptors so that it is available in the interceptor.
         | 
| 245 | 
            +
                        activity.instance = defn.instance.is_a?(Proc) ? defn.instance.call : defn.instance # steep:ignore
         | 
| 246 | 
            +
             | 
| 241 247 | 
             
                        # Build impl with interceptors
         | 
| 242 248 | 
             
                        # @type var impl: Temporalio::Worker::Interceptor::Activity::Inbound
         | 
| 243 249 | 
             
                        impl = InboundImplementation.new(self)
         | 
| @@ -255,7 +261,7 @@ module Temporalio | |
| 255 261 | 
             
                            result: @worker.options.client.data_converter.to_payload(result)
         | 
| 256 262 | 
             
                          )
         | 
| 257 263 | 
             
                        )
         | 
| 258 | 
            -
                      rescue Exception => e # rubocop:disable Lint/RescueException We are intending to catch everything here
         | 
| 264 | 
            +
                      rescue Exception => e # rubocop:disable Lint/RescueException -- We are intending to catch everything here
         | 
| 259 265 | 
             
                        if e.is_a?(Activity::CompleteAsyncError)
         | 
| 260 266 | 
             
                          # Wanting to complete async
         | 
| 261 267 | 
             
                          @scoped_logger.debug('Completing activity asynchronously')
         | 
| @@ -293,9 +299,10 @@ module Temporalio | |
| 293 299 |  | 
| 294 300 | 
             
                    class RunningActivity < Activity::Context
         | 
| 295 301 | 
             
                      attr_reader :info, :cancellation, :worker_shutdown_cancellation, :payload_converter, :logger
         | 
| 296 | 
            -
                      attr_accessor :_outbound_impl, :_server_requested_cancel
         | 
| 302 | 
            +
                      attr_accessor :instance, :_outbound_impl, :_server_requested_cancel
         | 
| 297 303 |  | 
| 298 304 | 
             
                      def initialize( # rubocop:disable Lint/MissingSuper
         | 
| 305 | 
            +
                        worker:,
         | 
| 299 306 | 
             
                        info:,
         | 
| 300 307 | 
             
                        cancellation:,
         | 
| 301 308 | 
             
                        worker_shutdown_cancellation:,
         | 
| @@ -303,6 +310,7 @@ module Temporalio | |
| 303 310 | 
             
                        logger:,
         | 
| 304 311 | 
             
                        runtime_metric_meter:
         | 
| 305 312 | 
             
                      )
         | 
| 313 | 
            +
                        @worker = worker
         | 
| 306 314 | 
             
                        @info = info
         | 
| 307 315 | 
             
                        @cancellation = cancellation
         | 
| 308 316 | 
             
                        @worker_shutdown_cancellation = worker_shutdown_cancellation
         | 
| @@ -331,6 +339,10 @@ module Temporalio | |
| 331 339 | 
             
                          }
         | 
| 332 340 | 
             
                        )
         | 
| 333 341 | 
             
                      end
         | 
| 342 | 
            +
             | 
| 343 | 
            +
                      def client
         | 
| 344 | 
            +
                        @worker.client
         | 
| 345 | 
            +
                      end
         | 
| 334 346 | 
             
                    end
         | 
| 335 347 |  | 
| 336 348 | 
             
                    class InboundImplementation < Temporalio::Worker::Interceptor::Activity::Inbound
         | 
| @@ -34,7 +34,7 @@ module Temporalio | |
| 34 34 | 
             
                                           rescue InjectEventForTesting => e
         | 
| 35 35 | 
             
                                             @queue.push(e.event)
         | 
| 36 36 | 
             
                                             @queue.push(Event::BlockSuccess.new(result: e))
         | 
| 37 | 
            -
                                           rescue Exception => e # rubocop:disable Lint/RescueException Intentionally catch all
         | 
| 37 | 
            +
                                           rescue Exception => e # rubocop:disable Lint/RescueException -- Intentionally catch all
         | 
| 38 38 | 
             
                                             @queue.push(Event::BlockFailure.new(error: e))
         | 
| 39 39 | 
             
                                           end
         | 
| 40 40 | 
             
                                         else
         | 
| @@ -43,7 +43,7 @@ module Temporalio | |
| 43 43 | 
             
                                           rescue InjectEventForTesting => e
         | 
| 44 44 | 
             
                                             @queue.push(e.event)
         | 
| 45 45 | 
             
                                             @queue.push(Event::BlockSuccess.new(result: e))
         | 
| 46 | 
            -
                                           rescue Exception => e # rubocop:disable Lint/RescueException Intentionally catch all
         | 
| 46 | 
            +
                                           rescue Exception => e # rubocop:disable Lint/RescueException -- Intentionally catch all
         | 
| 47 47 | 
             
                                             @queue.push(Event::BlockFailure.new(error: e))
         | 
| 48 48 | 
             
                                           end
         | 
| 49 49 | 
             
                                         end
         | 
| @@ -32,6 +32,16 @@ module Temporalio | |
| 32 32 | 
             
                        @instance.continue_as_new_suggested
         | 
| 33 33 | 
             
                      end
         | 
| 34 34 |  | 
| 35 | 
            +
                      def current_details
         | 
| 36 | 
            +
                        @instance.current_details || ''
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      def current_details=(details)
         | 
| 40 | 
            +
                        raise 'Details must be a String' unless details.nil? || details.is_a?(String)
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                        @instance.current_details = (details || '')
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
             | 
| 35 45 | 
             
                      def current_history_length
         | 
| 36 46 | 
             
                        @instance.current_history_length
         | 
| 37 47 | 
             
                      end
         | 
| @@ -52,6 +62,7 @@ module Temporalio | |
| 52 62 | 
             
                        activity,
         | 
| 53 63 | 
             
                        *args,
         | 
| 54 64 | 
             
                        task_queue:,
         | 
| 65 | 
            +
                        summary:,
         | 
| 55 66 | 
             
                        schedule_to_close_timeout:,
         | 
| 56 67 | 
             
                        schedule_to_start_timeout:,
         | 
| 57 68 | 
             
                        start_to_close_timeout:,
         | 
| @@ -62,11 +73,22 @@ module Temporalio | |
| 62 73 | 
             
                        activity_id:,
         | 
| 63 74 | 
             
                        disable_eager_execution:
         | 
| 64 75 | 
             
                      )
         | 
| 76 | 
            +
                        activity = case activity
         | 
| 77 | 
            +
                                   when Class
         | 
| 78 | 
            +
                                     Activity::Definition::Info.from_activity(activity).name&.to_s
         | 
| 79 | 
            +
                                   when Symbol, String
         | 
| 80 | 
            +
                                     activity.to_s
         | 
| 81 | 
            +
                                   else
         | 
| 82 | 
            +
                                     raise ArgumentError, 'Activity must be a definition class, or a symbol/string'
         | 
| 83 | 
            +
                                   end
         | 
| 84 | 
            +
                        raise 'Cannot invoke dynamic activities' unless activity
         | 
| 85 | 
            +
             | 
| 65 86 | 
             
                        @outbound.execute_activity(
         | 
| 66 87 | 
             
                          Temporalio::Worker::Interceptor::Workflow::ExecuteActivityInput.new(
         | 
| 67 88 | 
             
                            activity:,
         | 
| 68 89 | 
             
                            args:,
         | 
| 69 90 | 
             
                            task_queue: task_queue || info.task_queue,
         | 
| 91 | 
            +
                            summary:,
         | 
| 70 92 | 
             
                            schedule_to_close_timeout:,
         | 
| 71 93 | 
             
                            schedule_to_start_timeout:,
         | 
| 72 94 | 
             
                            start_to_close_timeout:,
         | 
| @@ -93,6 +115,16 @@ module Temporalio | |
| 93 115 | 
             
                        cancellation_type:,
         | 
| 94 116 | 
             
                        activity_id:
         | 
| 95 117 | 
             
                      )
         | 
| 118 | 
            +
                        activity = case activity
         | 
| 119 | 
            +
                                   when Class
         | 
| 120 | 
            +
                                     Activity::Definition::Info.from_activity(activity).name&.to_s
         | 
| 121 | 
            +
                                   when Symbol, String
         | 
| 122 | 
            +
                                     activity.to_s
         | 
| 123 | 
            +
                                   else
         | 
| 124 | 
            +
                                     raise ArgumentError, 'Activity must be a definition class, or a symbol/string'
         | 
| 125 | 
            +
                                   end
         | 
| 126 | 
            +
                        raise 'Cannot invoke dynamic activities' unless activity
         | 
| 127 | 
            +
             | 
| 96 128 | 
             
                        @outbound.execute_local_activity(
         | 
| 97 129 | 
             
                          Temporalio::Worker::Interceptor::Workflow::ExecuteLocalActivityInput.new(
         | 
| 98 130 | 
             
                            activity:,
         | 
| @@ -122,12 +154,26 @@ module Temporalio | |
| 122 154 | 
             
                        @instance.info
         | 
| 123 155 | 
             
                      end
         | 
| 124 156 |  | 
| 157 | 
            +
                      def instance
         | 
| 158 | 
            +
                        @instance.instance
         | 
| 159 | 
            +
                      end
         | 
| 160 | 
            +
             | 
| 125 161 | 
             
                      def initialize_continue_as_new_error(error)
         | 
| 126 162 | 
             
                        @outbound.initialize_continue_as_new_error(
         | 
| 127 163 | 
             
                          Temporalio::Worker::Interceptor::Workflow::InitializeContinueAsNewErrorInput.new(error:)
         | 
| 128 164 | 
             
                        )
         | 
| 129 165 | 
             
                      end
         | 
| 130 166 |  | 
| 167 | 
            +
                      def io_enabled(&)
         | 
| 168 | 
            +
                        prev = @instance.io_enabled
         | 
| 169 | 
            +
                        @instance.io_enabled = true
         | 
| 170 | 
            +
                        begin
         | 
| 171 | 
            +
                          yield
         | 
| 172 | 
            +
                        ensure
         | 
| 173 | 
            +
                          @instance.io_enabled = prev
         | 
| 174 | 
            +
                        end
         | 
| 175 | 
            +
                      end
         | 
| 176 | 
            +
             | 
| 131 177 | 
             
                      def logger
         | 
| 132 178 | 
             
                        @instance.logger
         | 
| 133 179 | 
             
                      end
         | 
| @@ -187,6 +233,8 @@ module Temporalio | |
| 187 233 | 
             
                        *args,
         | 
| 188 234 | 
             
                        id:,
         | 
| 189 235 | 
             
                        task_queue:,
         | 
| 236 | 
            +
                        static_summary:,
         | 
| 237 | 
            +
                        static_details:,
         | 
| 190 238 | 
             
                        cancellation:,
         | 
| 191 239 | 
             
                        cancellation_type:,
         | 
| 192 240 | 
             
                        parent_close_policy:,
         | 
| @@ -201,10 +249,12 @@ module Temporalio | |
| 201 249 | 
             
                      )
         | 
| 202 250 | 
             
                        @outbound.start_child_workflow(
         | 
| 203 251 | 
             
                          Temporalio::Worker::Interceptor::Workflow::StartChildWorkflowInput.new(
         | 
| 204 | 
            -
                            workflow | 
| 252 | 
            +
                            workflow: Workflow::Definition._workflow_type_from_workflow_parameter(workflow),
         | 
| 205 253 | 
             
                            args:,
         | 
| 206 254 | 
             
                            id:,
         | 
| 207 255 | 
             
                            task_queue:,
         | 
| 256 | 
            +
                            static_summary:,
         | 
| 257 | 
            +
                            static_details:,
         | 
| 208 258 | 
             
                            cancellation:,
         | 
| 209 259 | 
             
                            cancellation_type:,
         | 
| 210 260 | 
             
                            parent_close_policy:,
         | 
| @@ -221,6 +271,10 @@ module Temporalio | |
| 221 271 | 
             
                        )
         | 
| 222 272 | 
             
                      end
         | 
| 223 273 |  | 
| 274 | 
            +
                      def storage
         | 
| 275 | 
            +
                        @storage ||= {}
         | 
| 276 | 
            +
                      end
         | 
| 277 | 
            +
             | 
| 224 278 | 
             
                      def timeout(duration, exception_class, *exception_args, summary:, &)
         | 
| 225 279 | 
             
                        raise 'Block required for timeout' unless block_given?
         | 
| 226 280 |  | 
| @@ -302,7 +356,7 @@ module Temporalio | |
| 302 356 | 
             
                        @outbound.signal_child_workflow(
         | 
| 303 357 | 
             
                          Temporalio::Worker::Interceptor::Workflow::SignalChildWorkflowInput.new(
         | 
| 304 358 | 
             
                            id:,
         | 
| 305 | 
            -
                            signal | 
| 359 | 
            +
                            signal: Workflow::Definition::Signal._name_from_parameter(signal),
         | 
| 306 360 | 
             
                            args:,
         | 
| 307 361 | 
             
                            cancellation:,
         | 
| 308 362 | 
             
                            headers: {}
         | 
| @@ -315,7 +369,7 @@ module Temporalio | |
| 315 369 | 
             
                          Temporalio::Worker::Interceptor::Workflow::SignalExternalWorkflowInput.new(
         | 
| 316 370 | 
             
                            id:,
         | 
| 317 371 | 
             
                            run_id:,
         | 
| 318 | 
            -
                            signal | 
| 372 | 
            +
                            signal: Workflow::Definition::Signal._name_from_parameter(signal),
         | 
| 319 373 | 
             
                            args:,
         | 
| 320 374 | 
             
                            cancellation:,
         | 
| 321 375 | 
             
                            headers: {}
         | 
| @@ -8,7 +8,7 @@ module Temporalio | |
| 8 8 | 
             
                    class Details
         | 
| 9 9 | 
             
                      attr_reader :namespace, :task_queue, :definition, :initial_activation, :logger, :metric_meter,
         | 
| 10 10 | 
             
                                  :payload_converter, :failure_converter, :interceptors, :disable_eager_activity_execution,
         | 
| 11 | 
            -
                                  :illegal_calls, :workflow_failure_exception_types
         | 
| 11 | 
            +
                                  :illegal_calls, :workflow_failure_exception_types, :unsafe_workflow_io_enabled
         | 
| 12 12 |  | 
| 13 13 | 
             
                      def initialize(
         | 
| 14 14 | 
             
                        namespace:,
         | 
| @@ -22,7 +22,8 @@ module Temporalio | |
| 22 22 | 
             
                        interceptors:,
         | 
| 23 23 | 
             
                        disable_eager_activity_execution:,
         | 
| 24 24 | 
             
                        illegal_calls:,
         | 
| 25 | 
            -
                        workflow_failure_exception_types | 
| 25 | 
            +
                        workflow_failure_exception_types:,
         | 
| 26 | 
            +
                        unsafe_workflow_io_enabled:
         | 
| 26 27 | 
             
                      )
         | 
| 27 28 | 
             
                        @namespace = namespace
         | 
| 28 29 | 
             
                        @task_queue = task_queue
         | 
| @@ -36,6 +37,7 @@ module Temporalio | |
| 36 37 | 
             
                        @disable_eager_activity_execution = disable_eager_activity_execution
         | 
| 37 38 | 
             
                        @illegal_calls = illegal_calls
         | 
| 38 39 | 
             
                        @workflow_failure_exception_types = workflow_failure_exception_types
         | 
| 40 | 
            +
                        @unsafe_workflow_io_enabled = unsafe_workflow_io_enabled
         | 
| 39 41 | 
             
                      end
         | 
| 40 42 | 
             
                    end
         | 
| 41 43 | 
             
                  end
         | 
| @@ -56,16 +56,6 @@ module Temporalio | |
| 56 56 | 
             
                          raise ArgumentError, 'Activity must have schedule_to_close_timeout or start_to_close_timeout'
         | 
| 57 57 | 
             
                        end
         | 
| 58 58 |  | 
| 59 | 
            -
                        activity_type = case input.activity
         | 
| 60 | 
            -
                                        when Class
         | 
| 61 | 
            -
                                          Activity::Definition::Info.from_activity(input.activity).name
         | 
| 62 | 
            -
                                        when Symbol, String
         | 
| 63 | 
            -
                                          input.activity.to_s
         | 
| 64 | 
            -
                                        else
         | 
| 65 | 
            -
                                          raise ArgumentError, 'Activity must be a definition class, or a symbol/string'
         | 
| 66 | 
            -
                                        end
         | 
| 67 | 
            -
                        raise 'Cannot invoke dynamic activities' unless activity_type
         | 
| 68 | 
            -
             | 
| 69 59 | 
             
                        execute_activity_with_local_backoffs(local: false, cancellation: input.cancellation) do
         | 
| 70 60 | 
             
                          seq = (@activity_counter += 1)
         | 
| 71 61 | 
             
                          @instance.add_command(
         | 
| @@ -73,7 +63,7 @@ module Temporalio | |
| 73 63 | 
             
                              schedule_activity: Bridge::Api::WorkflowCommands::ScheduleActivity.new(
         | 
| 74 64 | 
             
                                seq:,
         | 
| 75 65 | 
             
                                activity_id: input.activity_id || seq.to_s,
         | 
| 76 | 
            -
                                activity_type | 
| 66 | 
            +
                                activity_type: input.activity,
         | 
| 77 67 | 
             
                                task_queue: input.task_queue,
         | 
| 78 68 | 
             
                                headers: ProtoUtils.headers_to_proto_hash(input.headers, @instance.payload_converter),
         | 
| 79 69 | 
             
                                arguments: ProtoUtils.convert_to_payload_array(@instance.payload_converter, input.args),
         | 
| @@ -84,7 +74,8 @@ module Temporalio | |
| 84 74 | 
             
                                retry_policy: input.retry_policy&._to_proto,
         | 
| 85 75 | 
             
                                cancellation_type: input.cancellation_type,
         | 
| 86 76 | 
             
                                do_not_eagerly_execute: input.disable_eager_execution
         | 
| 87 | 
            -
                              )
         | 
| 77 | 
            +
                              ),
         | 
| 78 | 
            +
                              user_metadata: ProtoUtils.to_user_metadata(input.summary, nil, @instance.payload_converter)
         | 
| 88 79 | 
             
                            )
         | 
| 89 80 | 
             
                          )
         | 
| 90 81 | 
             
                          seq
         | 
| @@ -96,16 +87,6 @@ module Temporalio | |
| 96 87 | 
             
                          raise ArgumentError, 'Activity must have schedule_to_close_timeout or start_to_close_timeout'
         | 
| 97 88 | 
             
                        end
         | 
| 98 89 |  | 
| 99 | 
            -
                        activity_type = case input.activity
         | 
| 100 | 
            -
                                        when Class
         | 
| 101 | 
            -
                                          Activity::Definition::Info.from_activity(input.activity).name
         | 
| 102 | 
            -
                                        when Symbol, String
         | 
| 103 | 
            -
                                          input.activity.to_s
         | 
| 104 | 
            -
                                        else
         | 
| 105 | 
            -
                                          raise ArgumentError, 'Activity must be a definition class, or a symbol/string'
         | 
| 106 | 
            -
                                        end
         | 
| 107 | 
            -
                        raise 'Cannot invoke dynamic activities' unless activity_type
         | 
| 108 | 
            -
             | 
| 109 90 | 
             
                        execute_activity_with_local_backoffs(local: true, cancellation: input.cancellation) do |do_backoff|
         | 
| 110 91 | 
             
                          seq = (@activity_counter += 1)
         | 
| 111 92 | 
             
                          @instance.add_command(
         | 
| @@ -113,7 +94,7 @@ module Temporalio | |
| 113 94 | 
             
                              schedule_local_activity: Bridge::Api::WorkflowCommands::ScheduleLocalActivity.new(
         | 
| 114 95 | 
             
                                seq:,
         | 
| 115 96 | 
             
                                activity_id: input.activity_id || seq.to_s,
         | 
| 116 | 
            -
                                activity_type | 
| 97 | 
            +
                                activity_type: input.activity,
         | 
| 117 98 | 
             
                                headers: ProtoUtils.headers_to_proto_hash(input.headers, @instance.payload_converter),
         | 
| 118 99 | 
             
                                arguments: ProtoUtils.convert_to_payload_array(@instance.payload_converter, input.args),
         | 
| 119 100 | 
             
                                schedule_to_close_timeout: ProtoUtils.seconds_to_duration(input.schedule_to_close_timeout),
         | 
| @@ -232,7 +213,7 @@ module Temporalio | |
| 232 213 | 
             
                        seq = (@external_signal_counter += 1)
         | 
| 233 214 | 
             
                        cmd = Bridge::Api::WorkflowCommands::SignalExternalWorkflowExecution.new(
         | 
| 234 215 | 
             
                          seq:,
         | 
| 235 | 
            -
                          signal_name:  | 
| 216 | 
            +
                          signal_name: signal,
         | 
| 236 217 | 
             
                          args: ProtoUtils.convert_to_payload_array(@instance.payload_converter, args),
         | 
| 237 218 | 
             
                          headers: ProtoUtils.headers_to_proto_hash(headers, @instance.payload_converter)
         | 
| 238 219 | 
             
                        )
         | 
| @@ -300,7 +281,8 @@ module Temporalio | |
| 300 281 | 
             
                            start_timer: Bridge::Api::WorkflowCommands::StartTimer.new(
         | 
| 301 282 | 
             
                              seq:,
         | 
| 302 283 | 
             
                              start_to_fire_timeout: ProtoUtils.seconds_to_duration(duration)
         | 
| 303 | 
            -
                            )
         | 
| 284 | 
            +
                            ),
         | 
| 285 | 
            +
                            user_metadata: ProtoUtils.to_user_metadata(input.summary, nil, @instance.payload_converter)
         | 
| 304 286 | 
             
                          )
         | 
| 305 287 | 
             
                        )
         | 
| 306 288 | 
             
                        @instance.pending_timers[seq] = Fiber.current
         | 
| @@ -340,7 +322,7 @@ module Temporalio | |
| 340 322 | 
             
                              seq:,
         | 
| 341 323 | 
             
                              namespace: @instance.info.namespace,
         | 
| 342 324 | 
             
                              workflow_id: input.id,
         | 
| 343 | 
            -
                              workflow_type:  | 
| 325 | 
            +
                              workflow_type: input.workflow,
         | 
| 344 326 | 
             
                              task_queue: input.task_queue,
         | 
| 345 327 | 
             
                              input: ProtoUtils.convert_to_payload_array(@instance.payload_converter, input.args),
         | 
| 346 328 | 
             
                              workflow_execution_timeout: ProtoUtils.seconds_to_duration(input.execution_timeout),
         | 
| @@ -354,6 +336,9 @@ module Temporalio | |
| 354 336 | 
             
                              memo: ProtoUtils.memo_to_proto_hash(input.memo, @instance.payload_converter),
         | 
| 355 337 | 
             
                              search_attributes: input.search_attributes&._to_proto_hash,
         | 
| 356 338 | 
             
                              cancellation_type: input.cancellation_type
         | 
| 339 | 
            +
                            ),
         | 
| 340 | 
            +
                            user_metadata: ProtoUtils.to_user_metadata(
         | 
| 341 | 
            +
                              input.static_summary, input.static_details, @instance.payload_converter
         | 
| 357 342 | 
             
                            )
         | 
| 358 343 | 
             
                          )
         | 
| 359 344 | 
             
                        )
         | 
| @@ -137,8 +137,28 @@ module Temporalio | |
| 137 137 | 
             
                      end
         | 
| 138 138 |  | 
| 139 139 | 
             
                      def io_wait(io, events, timeout)
         | 
| 140 | 
            -
                        #  | 
| 141 | 
            -
                         | 
| 140 | 
            +
                        # Do not allow if IO disabled
         | 
| 141 | 
            +
                        unless @instance.io_enabled
         | 
| 142 | 
            +
                          raise Workflow::NondeterminismError,
         | 
| 143 | 
            +
                                'Cannot perform IO from inside a workflow. If this is known to be safe, ' \
         | 
| 144 | 
            +
                                'the code can be run in a Temporalio::Workflow::Unsafe.io_enabled block.'
         | 
| 145 | 
            +
                        end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                        # Use regular Ruby behavior of blocking this thread. There is no Ruby implementation of io_wait we can just
         | 
| 148 | 
            +
                        # delegate to at this time (or default scheduler or anything like that), so we had to implement this
         | 
| 149 | 
            +
                        # ourselves.
         | 
| 150 | 
            +
                        readers = events.nobits?(IO::READABLE) ? nil : [io]
         | 
| 151 | 
            +
                        writers = events.nobits?(IO::WRITABLE) ? nil : [io]
         | 
| 152 | 
            +
                        priority = events.nobits?(IO::PRIORITY) ? nil : [io]
         | 
| 153 | 
            +
                        ready = IO.select(readers, writers, priority, timeout) # steep:ignore
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                        result = 0
         | 
| 156 | 
            +
                        unless ready.nil?
         | 
| 157 | 
            +
                          result |= IO::READABLE if ready[0]&.include?(io)
         | 
| 158 | 
            +
                          result |= IO::WRITABLE if ready[1]&.include?(io)
         | 
| 159 | 
            +
                          result |= IO::PRIORITY if ready[2]&.include?(io)
         | 
| 160 | 
            +
                        end
         | 
| 161 | 
            +
                        result
         | 
| 142 162 | 
             
                      end
         | 
| 143 163 |  | 
| 144 164 | 
             
                      def kernel_sleep(duration = nil)
         | 
| @@ -4,6 +4,7 @@ require 'json' | |
| 4 4 | 
             
            require 'temporalio'
         | 
| 5 5 | 
             
            require 'temporalio/activity/definition'
         | 
| 6 6 | 
             
            require 'temporalio/api'
         | 
| 7 | 
            +
            require 'temporalio/converters/payload_converter'
         | 
| 7 8 | 
             
            require 'temporalio/converters/raw_value'
         | 
| 8 9 | 
             
            require 'temporalio/error'
         | 
| 9 10 | 
             
            require 'temporalio/internal/bridge/api'
         | 
| @@ -56,6 +57,7 @@ module Temporalio | |
| 56 57 | 
             
                                :failure_converter, :cancellation, :continue_as_new_suggested, :current_history_length,
         | 
| 57 58 | 
             
                                :current_history_size, :replaying, :random, :signal_handlers, :query_handlers, :update_handlers,
         | 
| 58 59 | 
             
                                :context_frozen
         | 
| 60 | 
            +
                    attr_accessor :io_enabled, :current_details
         | 
| 59 61 |  | 
| 60 62 | 
             
                    def initialize(details)
         | 
| 61 63 | 
             
                      # Initialize general state
         | 
| @@ -66,6 +68,7 @@ module Temporalio | |
| 66 68 | 
             
                      @logger = ReplaySafeLogger.new(logger: details.logger, instance: self)
         | 
| 67 69 | 
             
                      @logger.scoped_values_getter = proc { scoped_logger_info }
         | 
| 68 70 | 
             
                      @runtime_metric_meter = details.metric_meter
         | 
| 71 | 
            +
                      @io_enabled = details.unsafe_workflow_io_enabled
         | 
| 69 72 | 
             
                      @scheduler = Scheduler.new(self)
         | 
| 70 73 | 
             
                      @payload_converter = details.payload_converter
         | 
| 71 74 | 
             
                      @failure_converter = details.failure_converter
         | 
| @@ -115,6 +118,7 @@ module Temporalio | |
| 115 118 | 
             
                          continued_run_id: ProtoUtils.string_or(@init_job.continued_from_execution_run_id),
         | 
| 116 119 | 
             
                          cron_schedule: ProtoUtils.string_or(@init_job.cron_schedule),
         | 
| 117 120 | 
             
                          execution_timeout: ProtoUtils.duration_to_seconds(@init_job.workflow_execution_timeout),
         | 
| 121 | 
            +
                          headers: ProtoUtils.headers_from_proto_map(@init_job.headers, @payload_converter) || {},
         | 
| 118 122 | 
             
                          last_failure: if @init_job.continued_failure
         | 
| 119 123 | 
             
                                          @failure_converter.from_failure(@init_job.continued_failure, @payload_converter)
         | 
| 120 124 | 
             
                                        end,
         | 
| @@ -130,6 +134,12 @@ module Temporalio | |
| 130 134 | 
             
                                    )
         | 
| 131 135 | 
             
                                  end,
         | 
| 132 136 | 
             
                          retry_policy: (RetryPolicy._from_proto(@init_job.retry_policy) if @init_job.retry_policy),
         | 
| 137 | 
            +
                          root: if @init_job.root_workflow
         | 
| 138 | 
            +
                                  Workflow::Info::RootInfo.new(
         | 
| 139 | 
            +
                                    run_id: @init_job.root_workflow.run_id,
         | 
| 140 | 
            +
                                    workflow_id: @init_job.root_workflow.workflow_id
         | 
| 141 | 
            +
                                  )
         | 
| 142 | 
            +
                                end,
         | 
| 133 143 | 
             
                          run_id: details.initial_activation.run_id,
         | 
| 134 144 | 
             
                          run_timeout: ProtoUtils.duration_to_seconds(@init_job.workflow_run_timeout),
         | 
| 135 145 | 
             
                          start_time: ProtoUtils.timestamp_to_time(details.initial_activation.timestamp) || raise,
         | 
| @@ -348,7 +358,10 @@ module Temporalio | |
| 348 358 | 
             
                    end
         | 
| 349 359 |  | 
| 350 360 | 
             
                    def apply_signal(job)
         | 
| 351 | 
            -
                       | 
| 361 | 
            +
                      # Get signal definition, falling back to dynamic if not present and not reserved
         | 
| 362 | 
            +
                      defn = signal_handlers[job.signal_name]
         | 
| 363 | 
            +
                      defn = signal_handlers[nil] if !defn && !Internal::ProtoUtils.reserved_name?(job.signal_name)
         | 
| 364 | 
            +
             | 
| 352 365 | 
             
                      handler_exec =
         | 
| 353 366 | 
             
                        if defn
         | 
| 354 367 | 
             
                          HandlerExecution.new(name: job.signal_name, update_id: nil, unfinished_policy: defn.unfinished_policy)
         | 
| @@ -381,37 +394,41 @@ module Temporalio | |
| 381 394 | 
             
                    end
         | 
| 382 395 |  | 
| 383 396 | 
             
                    def apply_query(job)
         | 
| 384 | 
            -
                      # TODO(cretz): __temporal_workflow_metadata
         | 
| 385 | 
            -
                      defn = case job.query_type
         | 
| 386 | 
            -
                             when '__stack_trace'
         | 
| 387 | 
            -
                               Workflow::Definition::Query.new(
         | 
| 388 | 
            -
                                 name: '__stack_trace',
         | 
| 389 | 
            -
                                 to_invoke: proc { scheduler.stack_trace }
         | 
| 390 | 
            -
                               )
         | 
| 391 | 
            -
                             else
         | 
| 392 | 
            -
                               query_handlers[job.query_type] || query_handlers[nil]
         | 
| 393 | 
            -
                             end
         | 
| 394 397 | 
             
                      schedule do
         | 
| 395 | 
            -
                         | 
| 396 | 
            -
             | 
| 397 | 
            -
             | 
| 398 | 
            -
             | 
| 398 | 
            +
                        # If it's a built-in, run it without interceptors, otherwise do normal behavior
         | 
| 399 | 
            +
                        result = if job.query_type == '__stack_trace'
         | 
| 400 | 
            +
                                   # Use raw value built from default converter because we don't want to use user-conversion
         | 
| 401 | 
            +
                                   Converters::RawValue.new(Converters::PayloadConverter.default.to_payload(scheduler.stack_trace))
         | 
| 402 | 
            +
                                 elsif job.query_type == '__temporal_workflow_metadata'
         | 
| 403 | 
            +
                                   # Use raw value built from default converter because we don't want to use user-conversion
         | 
| 404 | 
            +
                                   Converters::RawValue.new(Converters::PayloadConverter.default.to_payload(workflow_metadata))
         | 
| 405 | 
            +
                                 else
         | 
| 406 | 
            +
                                   # Get query definition, falling back to dynamic if not present and not reserved
         | 
| 407 | 
            +
                                   defn = query_handlers[job.query_type]
         | 
| 408 | 
            +
                                   defn = query_handlers[nil] if !defn && !Internal::ProtoUtils.reserved_name?(job.query_type)
         | 
| 409 | 
            +
             | 
| 410 | 
            +
                                   unless defn
         | 
| 411 | 
            +
                                     raise "Query handler for #{job.query_type} expected but not found, " \
         | 
| 412 | 
            +
                                           "known queries: [#{query_handlers.keys.compact.sort.join(', ')}]"
         | 
| 413 | 
            +
                                   end
         | 
| 414 | 
            +
             | 
| 415 | 
            +
                                   with_context_frozen do
         | 
| 416 | 
            +
                                     @inbound.handle_query(
         | 
| 417 | 
            +
                                       Temporalio::Worker::Interceptor::Workflow::HandleQueryInput.new(
         | 
| 418 | 
            +
                                         id: job.query_id,
         | 
| 419 | 
            +
                                         query: job.query_type,
         | 
| 420 | 
            +
                                         args: begin
         | 
| 421 | 
            +
                                           convert_handler_args(payload_array: job.arguments, defn:)
         | 
| 422 | 
            +
                                         rescue StandardError => e
         | 
| 423 | 
            +
                                           raise "Failed converting query input arguments: #{e}"
         | 
| 424 | 
            +
                                         end,
         | 
| 425 | 
            +
                                         definition: defn,
         | 
| 426 | 
            +
                                         headers: ProtoUtils.headers_from_proto_map(job.headers, @payload_converter) || {}
         | 
| 427 | 
            +
                                       )
         | 
| 428 | 
            +
                                     )
         | 
| 429 | 
            +
                                   end
         | 
| 430 | 
            +
                                 end
         | 
| 399 431 |  | 
| 400 | 
            -
                        result = with_context_frozen do
         | 
| 401 | 
            -
                          @inbound.handle_query(
         | 
| 402 | 
            -
                            Temporalio::Worker::Interceptor::Workflow::HandleQueryInput.new(
         | 
| 403 | 
            -
                              id: job.query_id,
         | 
| 404 | 
            -
                              query: job.query_type,
         | 
| 405 | 
            -
                              args: begin
         | 
| 406 | 
            -
                                convert_handler_args(payload_array: job.arguments, defn:)
         | 
| 407 | 
            -
                              rescue StandardError => e
         | 
| 408 | 
            -
                                raise "Failed converting query input arguments: #{e}"
         | 
| 409 | 
            -
                              end,
         | 
| 410 | 
            -
                              definition: defn,
         | 
| 411 | 
            -
                              headers: ProtoUtils.headers_from_proto_map(job.headers, @payload_converter) || {}
         | 
| 412 | 
            -
                            )
         | 
| 413 | 
            -
                          )
         | 
| 414 | 
            -
                        end
         | 
| 415 432 | 
             
                        add_command(
         | 
| 416 433 | 
             
                          Bridge::Api::WorkflowCommands::WorkflowCommand.new(
         | 
| 417 434 | 
             
                            respond_to_query: Bridge::Api::WorkflowCommands::QueryResult.new(
         | 
| @@ -435,7 +452,10 @@ module Temporalio | |
| 435 452 | 
             
                    end
         | 
| 436 453 |  | 
| 437 454 | 
             
                    def apply_update(job)
         | 
| 438 | 
            -
                       | 
| 455 | 
            +
                      # Get update definition, falling back to dynamic if not present and not reserved
         | 
| 456 | 
            +
                      defn = update_handlers[job.name]
         | 
| 457 | 
            +
                      defn = update_handlers[nil] if !defn && !Internal::ProtoUtils.reserved_name?(job.name)
         | 
| 458 | 
            +
             | 
| 439 459 | 
             
                      handler_exec =
         | 
| 440 460 | 
             
                        (HandlerExecution.new(name: job.name, update_id: job.id, unfinished_policy: defn.unfinished_policy) if defn)
         | 
| 441 461 | 
             
                      schedule(handler_exec:) do
         | 
| @@ -527,7 +547,7 @@ module Temporalio | |
| 527 547 | 
             
                      result = @inbound.execute(
         | 
| 528 548 | 
             
                        Temporalio::Worker::Interceptor::Workflow::ExecuteInput.new(
         | 
| 529 549 | 
             
                          args: @workflow_arguments,
         | 
| 530 | 
            -
                          headers:  | 
| 550 | 
            +
                          headers: @info.headers
         | 
| 531 551 | 
             
                        )
         | 
| 532 552 | 
             
                      )
         | 
| 533 553 | 
             
                      add_command(
         | 
| @@ -671,6 +691,30 @@ module Temporalio | |
| 671 691 | 
             
                      end
         | 
| 672 692 | 
             
                    end
         | 
| 673 693 |  | 
| 694 | 
            +
                    def workflow_metadata
         | 
| 695 | 
            +
                      Temporalio::Api::Sdk::V1::WorkflowMetadata.new(
         | 
| 696 | 
            +
                        definition: Temporalio::Api::Sdk::V1::WorkflowDefinition.new(
         | 
| 697 | 
            +
                          type: info.workflow_type,
         | 
| 698 | 
            +
                          query_definitions: query_handlers.values.map do |defn|
         | 
| 699 | 
            +
                            Temporalio::Api::Sdk::V1::WorkflowInteractionDefinition.new(
         | 
| 700 | 
            +
                              name: defn.name || '', description: defn.description || ''
         | 
| 701 | 
            +
                            )
         | 
| 702 | 
            +
                          end,
         | 
| 703 | 
            +
                          signal_definitions: signal_handlers.values.map do |defn|
         | 
| 704 | 
            +
                            Temporalio::Api::Sdk::V1::WorkflowInteractionDefinition.new(
         | 
| 705 | 
            +
                              name: defn.name || '', description: defn.description || ''
         | 
| 706 | 
            +
                            )
         | 
| 707 | 
            +
                          end,
         | 
| 708 | 
            +
                          update_definitions: update_handlers.values.map do |defn|
         | 
| 709 | 
            +
                            Temporalio::Api::Sdk::V1::WorkflowInteractionDefinition.new(
         | 
| 710 | 
            +
                              name: defn.name || '', description: defn.description || ''
         | 
| 711 | 
            +
                            )
         | 
| 712 | 
            +
                          end
         | 
| 713 | 
            +
                        ),
         | 
| 714 | 
            +
                        current_details: current_details || ''
         | 
| 715 | 
            +
                      )
         | 
| 716 | 
            +
                    end
         | 
| 717 | 
            +
             | 
| 674 718 | 
             
                    def scoped_logger_info
         | 
| 675 719 | 
             
                      @scoped_logger_info ||= {
         | 
| 676 720 | 
             
                        attempt: info.attempt,
         |