temporalio 0.3.0-x86_64-linux-musl → 0.4.0-x86_64-linux-musl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/Rakefile +1 -1
- data/lib/temporalio/activity/context.rb +7 -0
- data/lib/temporalio/activity/definition.rb +4 -1
- 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.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_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 +14 -5
- data/lib/temporalio/internal/worker/multi_runner.rb +2 -2
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +53 -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 +6 -3
- 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 +32 -8
- 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/workflow_executor/thread_pool.rb +8 -3
- data/lib/temporalio/worker/workflow_replayer.rb +7 -0
- data/lib/temporalio/worker.rb +34 -0
- 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 +54 -8
- data/temporalio.gemspec +2 -1
- metadata +24 -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,
         | 
| @@ -211,7 +214,7 @@ module Temporalio | |
| 211 214 | 
             
                      Activity::Context._current_executor&.set_activity_context(defn, activity)
         | 
| 212 215 | 
             
                      set_running_activity(task_token, activity)
         | 
| 213 216 | 
             
                      run_activity(defn, activity, input)
         | 
| 214 | 
            -
                    rescue Exception => e # rubocop:disable Lint/RescueException We are intending to catch everything here
         | 
| 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
         | 
| @@ -258,7 +261,7 @@ module Temporalio | |
| 258 261 | 
             
                            result: @worker.options.client.data_converter.to_payload(result)
         | 
| 259 262 | 
             
                          )
         | 
| 260 263 | 
             
                        )
         | 
| 261 | 
            -
                      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
         | 
| 262 265 | 
             
                        if e.is_a?(Activity::CompleteAsyncError)
         | 
| 263 266 | 
             
                          # Wanting to complete async
         | 
| 264 267 | 
             
                          @scoped_logger.debug('Completing activity asynchronously')
         | 
| @@ -299,6 +302,7 @@ module Temporalio | |
| 299 302 | 
             
                      attr_accessor :instance, :_outbound_impl, :_server_requested_cancel
         | 
| 300 303 |  | 
| 301 304 | 
             
                      def initialize( # rubocop:disable Lint/MissingSuper
         | 
| 305 | 
            +
                        worker:,
         | 
| 302 306 | 
             
                        info:,
         | 
| 303 307 | 
             
                        cancellation:,
         | 
| 304 308 | 
             
                        worker_shutdown_cancellation:,
         | 
| @@ -306,6 +310,7 @@ module Temporalio | |
| 306 310 | 
             
                        logger:,
         | 
| 307 311 | 
             
                        runtime_metric_meter:
         | 
| 308 312 | 
             
                      )
         | 
| 313 | 
            +
                        @worker = worker
         | 
| 309 314 | 
             
                        @info = info
         | 
| 310 315 | 
             
                        @cancellation = cancellation
         | 
| 311 316 | 
             
                        @worker_shutdown_cancellation = worker_shutdown_cancellation
         | 
| @@ -334,6 +339,10 @@ module Temporalio | |
| 334 339 | 
             
                          }
         | 
| 335 340 | 
             
                        )
         | 
| 336 341 | 
             
                      end
         | 
| 342 | 
            +
             | 
| 343 | 
            +
                      def client
         | 
| 344 | 
            +
                        @worker.client
         | 
| 345 | 
            +
                      end
         | 
| 337 346 | 
             
                    end
         | 
| 338 347 |  | 
| 339 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:,
         | 
| @@ -132,6 +164,16 @@ module Temporalio | |
| 132 164 | 
             
                        )
         | 
| 133 165 | 
             
                      end
         | 
| 134 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 | 
            +
             | 
| 135 177 | 
             
                      def logger
         | 
| 136 178 | 
             
                        @instance.logger
         | 
| 137 179 | 
             
                      end
         | 
| @@ -191,6 +233,8 @@ module Temporalio | |
| 191 233 | 
             
                        *args,
         | 
| 192 234 | 
             
                        id:,
         | 
| 193 235 | 
             
                        task_queue:,
         | 
| 236 | 
            +
                        static_summary:,
         | 
| 237 | 
            +
                        static_details:,
         | 
| 194 238 | 
             
                        cancellation:,
         | 
| 195 239 | 
             
                        cancellation_type:,
         | 
| 196 240 | 
             
                        parent_close_policy:,
         | 
| @@ -205,10 +249,12 @@ module Temporalio | |
| 205 249 | 
             
                      )
         | 
| 206 250 | 
             
                        @outbound.start_child_workflow(
         | 
| 207 251 | 
             
                          Temporalio::Worker::Interceptor::Workflow::StartChildWorkflowInput.new(
         | 
| 208 | 
            -
                            workflow | 
| 252 | 
            +
                            workflow: Workflow::Definition._workflow_type_from_workflow_parameter(workflow),
         | 
| 209 253 | 
             
                            args:,
         | 
| 210 254 | 
             
                            id:,
         | 
| 211 255 | 
             
                            task_queue:,
         | 
| 256 | 
            +
                            static_summary:,
         | 
| 257 | 
            +
                            static_details:,
         | 
| 212 258 | 
             
                            cancellation:,
         | 
| 213 259 | 
             
                            cancellation_type:,
         | 
| 214 260 | 
             
                            parent_close_policy:,
         | 
| @@ -225,6 +271,10 @@ module Temporalio | |
| 225 271 | 
             
                        )
         | 
| 226 272 | 
             
                      end
         | 
| 227 273 |  | 
| 274 | 
            +
                      def storage
         | 
| 275 | 
            +
                        @storage ||= {}
         | 
| 276 | 
            +
                      end
         | 
| 277 | 
            +
             | 
| 228 278 | 
             
                      def timeout(duration, exception_class, *exception_args, summary:, &)
         | 
| 229 279 | 
             
                        raise 'Block required for timeout' unless block_given?
         | 
| 230 280 |  | 
| @@ -306,7 +356,7 @@ module Temporalio | |
| 306 356 | 
             
                        @outbound.signal_child_workflow(
         | 
| 307 357 | 
             
                          Temporalio::Worker::Interceptor::Workflow::SignalChildWorkflowInput.new(
         | 
| 308 358 | 
             
                            id:,
         | 
| 309 | 
            -
                            signal | 
| 359 | 
            +
                            signal: Workflow::Definition::Signal._name_from_parameter(signal),
         | 
| 310 360 | 
             
                            args:,
         | 
| 311 361 | 
             
                            cancellation:,
         | 
| 312 362 | 
             
                            headers: {}
         | 
| @@ -319,7 +369,7 @@ module Temporalio | |
| 319 369 | 
             
                          Temporalio::Worker::Interceptor::Workflow::SignalExternalWorkflowInput.new(
         | 
| 320 370 | 
             
                            id:,
         | 
| 321 371 | 
             
                            run_id:,
         | 
| 322 | 
            -
                            signal | 
| 372 | 
            +
                            signal: Workflow::Definition::Signal._name_from_parameter(signal),
         | 
| 323 373 | 
             
                            args:,
         | 
| 324 374 | 
             
                            cancellation:,
         | 
| 325 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,
         | 
| @@ -67,6 +67,7 @@ module Temporalio | |
| 67 67 | 
             
                      illegal_workflow_calls:,
         | 
| 68 68 | 
             
                      workflow_failure_exception_types:,
         | 
| 69 69 | 
             
                      workflow_payload_codec_thread_pool:,
         | 
| 70 | 
            +
                      unsafe_workflow_io_enabled:,
         | 
| 70 71 | 
             
                      debug_mode:,
         | 
| 71 72 | 
             
                      on_eviction: nil
         | 
| 72 73 | 
             
                    )
         | 
| @@ -109,7 +110,8 @@ module Temporalio | |
| 109 110 | 
             
                          end
         | 
| 110 111 |  | 
| 111 112 | 
             
                          t
         | 
| 112 | 
            -
                        end.freeze
         | 
| 113 | 
            +
                        end.freeze,
         | 
| 114 | 
            +
                        unsafe_workflow_io_enabled:
         | 
| 113 115 | 
             
                      )
         | 
| 114 116 | 
             
                      @state.on_eviction = on_eviction if on_eviction
         | 
| 115 117 |  | 
| @@ -184,14 +186,14 @@ module Temporalio | |
| 184 186 | 
             
                    class State
         | 
| 185 187 | 
             
                      attr_reader :workflow_definitions, :bridge_worker, :logger, :metric_meter, :data_converter, :deadlock_timeout,
         | 
| 186 188 | 
             
                                  :illegal_calls, :namespace, :task_queue, :disable_eager_activity_execution,
         | 
| 187 | 
            -
                                  :workflow_interceptors, :workflow_failure_exception_types
         | 
| 189 | 
            +
                                  :workflow_interceptors, :workflow_failure_exception_types, :unsafe_workflow_io_enabled
         | 
| 188 190 |  | 
| 189 191 | 
             
                      attr_writer :on_eviction
         | 
| 190 192 |  | 
| 191 193 | 
             
                      def initialize(
         | 
| 192 194 | 
             
                        workflow_definitions:, bridge_worker:, logger:, metric_meter:, data_converter:, deadlock_timeout:,
         | 
| 193 195 | 
             
                        illegal_calls:, namespace:, task_queue:, disable_eager_activity_execution:,
         | 
| 194 | 
            -
                        workflow_interceptors:, workflow_failure_exception_types:
         | 
| 196 | 
            +
                        workflow_interceptors:, workflow_failure_exception_types:, unsafe_workflow_io_enabled:
         | 
| 195 197 | 
             
                      )
         | 
| 196 198 | 
             
                        @workflow_definitions = workflow_definitions
         | 
| 197 199 | 
             
                        @bridge_worker = bridge_worker
         | 
| @@ -205,6 +207,7 @@ module Temporalio | |
| 205 207 | 
             
                        @disable_eager_activity_execution = disable_eager_activity_execution
         | 
| 206 208 | 
             
                        @workflow_interceptors = workflow_interceptors
         | 
| 207 209 | 
             
                        @workflow_failure_exception_types = workflow_failure_exception_types
         | 
| 210 | 
            +
                        @unsafe_workflow_io_enabled = unsafe_workflow_io_enabled
         | 
| 208 211 |  | 
| 209 212 | 
             
                        @running_workflows = {}
         | 
| 210 213 | 
             
                        @running_workflows_mutex = Mutex.new
         |