temporalio 0.2.0-x86_64-darwin → 0.3.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/.yardopts +2 -0
- data/Gemfile +3 -3
- data/Rakefile +10 -296
- data/lib/temporalio/activity/complete_async_error.rb +1 -1
- data/lib/temporalio/activity/context.rb +5 -2
- data/lib/temporalio/activity/definition.rb +163 -65
- data/lib/temporalio/activity/info.rb +22 -21
- data/lib/temporalio/activity.rb +2 -59
- data/lib/temporalio/api/activity/v1/message.rb +25 -0
- data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +34 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
- data/lib/temporalio/api/cloud/identity/v1/message.rb +6 -1
- data/lib/temporalio/api/cloud/namespace/v1/message.rb +8 -1
- data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
- data/lib/temporalio/api/cloud/operation/v1/message.rb +2 -1
- data/lib/temporalio/api/cloud/region/v1/message.rb +2 -1
- data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
- data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
- data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
- data/lib/temporalio/api/common/v1/message.rb +7 -1
- 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/reset.rb +1 -1
- data/lib/temporalio/api/history/v1/message.rb +1 -1
- data/lib/temporalio/api/nexus/v1/message.rb +2 -2
- data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
- data/lib/temporalio/api/payload_visitor.rb +1513 -0
- data/lib/temporalio/api/schedule/v1/message.rb +2 -1
- data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
- data/lib/temporalio/api/testservice/v1/service.rb +23 -0
- data/lib/temporalio/api/workflow/v1/message.rb +1 -1
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +17 -2
- data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
- data/lib/temporalio/api.rb +1 -0
- data/lib/temporalio/cancellation.rb +34 -14
- data/lib/temporalio/client/async_activity_handle.rb +12 -37
- data/lib/temporalio/client/connection/cloud_service.rb +309 -231
- data/lib/temporalio/client/connection/operator_service.rb +36 -84
- data/lib/temporalio/client/connection/service.rb +6 -5
- data/lib/temporalio/client/connection/test_service.rb +111 -0
- data/lib/temporalio/client/connection/workflow_service.rb +264 -441
- data/lib/temporalio/client/connection.rb +90 -44
- data/lib/temporalio/client/interceptor.rb +160 -60
- data/lib/temporalio/client/schedule.rb +967 -0
- data/lib/temporalio/client/schedule_handle.rb +126 -0
- data/lib/temporalio/client/workflow_execution.rb +7 -10
- data/lib/temporalio/client/workflow_handle.rb +38 -95
- data/lib/temporalio/client/workflow_update_handle.rb +3 -5
- data/lib/temporalio/client.rb +122 -42
- data/lib/temporalio/common_enums.rb +17 -0
- data/lib/temporalio/converters/data_converter.rb +4 -7
- data/lib/temporalio/converters/failure_converter.rb +5 -3
- data/lib/temporalio/converters/payload_converter/composite.rb +4 -0
- data/lib/temporalio/converters/payload_converter.rb +6 -8
- data/lib/temporalio/converters/raw_value.rb +20 -0
- data/lib/temporalio/error/failure.rb +1 -1
- data/lib/temporalio/error.rb +10 -2
- 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.1 → 3.4}/temporalio_bridge.bundle +0 -0
- data/lib/temporalio/internal/bridge/api/core_interface.rb +5 -1
- data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +5 -1
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +4 -1
- data/lib/temporalio/internal/bridge/client.rb +11 -6
- data/lib/temporalio/internal/bridge/testing.rb +20 -0
- data/lib/temporalio/internal/bridge/worker.rb +2 -0
- data/lib/temporalio/internal/bridge.rb +1 -1
- data/lib/temporalio/internal/client/implementation.rb +245 -70
- data/lib/temporalio/internal/metric.rb +122 -0
- data/lib/temporalio/internal/proto_utils.rb +86 -7
- data/lib/temporalio/internal/worker/activity_worker.rb +52 -24
- data/lib/temporalio/internal/worker/multi_runner.rb +51 -7
- data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +329 -0
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +44 -0
- data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
- data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
- data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +415 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +163 -0
- data/lib/temporalio/internal/worker/workflow_instance.rb +730 -0
- data/lib/temporalio/internal/worker/workflow_worker.rb +196 -0
- data/lib/temporalio/metric.rb +109 -0
- data/lib/temporalio/retry_policy.rb +37 -14
- data/lib/temporalio/runtime.rb +118 -75
- data/lib/temporalio/search_attributes.rb +80 -37
- data/lib/temporalio/testing/activity_environment.rb +2 -2
- data/lib/temporalio/testing/workflow_environment.rb +251 -5
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/activity_executor/thread_pool.rb +9 -217
- data/lib/temporalio/worker/activity_executor.rb +3 -3
- data/lib/temporalio/worker/interceptor.rb +340 -66
- data/lib/temporalio/worker/thread_pool.rb +237 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +230 -0
- data/lib/temporalio/worker/workflow_executor.rb +26 -0
- data/lib/temporalio/worker.rb +201 -30
- data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
- data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
- data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
- data/lib/temporalio/workflow/definition.rb +566 -0
- data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
- data/lib/temporalio/workflow/future.rb +151 -0
- data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
- data/lib/temporalio/workflow/info.rb +82 -0
- data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
- data/lib/temporalio/workflow/update_info.rb +20 -0
- data/lib/temporalio/workflow.rb +523 -0
- data/lib/temporalio.rb +4 -0
- data/temporalio.gemspec +2 -2
- metadata +52 -6
| @@ -0,0 +1,196 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'temporalio/api/payload_visitor'
         | 
| 4 | 
            +
            require 'temporalio/error'
         | 
| 5 | 
            +
            require 'temporalio/internal/worker/workflow_instance'
         | 
| 6 | 
            +
            require 'temporalio/scoped_logger'
         | 
| 7 | 
            +
            require 'temporalio/workflow'
         | 
| 8 | 
            +
            require 'temporalio/workflow/definition'
         | 
| 9 | 
            +
            require 'timeout'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            module Temporalio
         | 
| 12 | 
            +
              module Internal
         | 
| 13 | 
            +
                module Worker
         | 
| 14 | 
            +
                  # Worker for handling workflow activations. Most activation work is delegated to the workflow executor.
         | 
| 15 | 
            +
                  class WorkflowWorker
         | 
| 16 | 
            +
                    def self.workflow_definitions(workflows)
         | 
| 17 | 
            +
                      workflows.each_with_object({}) do |workflow, hash|
         | 
| 18 | 
            +
                        # Load definition
         | 
| 19 | 
            +
                        defn = begin
         | 
| 20 | 
            +
                          if workflow.is_a?(Workflow::Definition::Info)
         | 
| 21 | 
            +
                            workflow
         | 
| 22 | 
            +
                          else
         | 
| 23 | 
            +
                            Workflow::Definition::Info.from_class(workflow)
         | 
| 24 | 
            +
                          end
         | 
| 25 | 
            +
                        rescue StandardError
         | 
| 26 | 
            +
                          raise ArgumentError, "Failed loading workflow #{workflow}"
         | 
| 27 | 
            +
                        end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                        # Confirm name not in use
         | 
| 30 | 
            +
                        raise ArgumentError, "Multiple workflows named #{defn.name || '<dynamic>'}" if hash.key?(defn.name)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                        hash[defn.name] = defn
         | 
| 33 | 
            +
                      end
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    def initialize(worker:, bridge_worker:, workflow_definitions:)
         | 
| 37 | 
            +
                      @executor = worker.options.workflow_executor
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      payload_codec = worker.options.client.data_converter.payload_codec
         | 
| 40 | 
            +
                      @workflow_payload_codec_thread_pool = worker.options.workflow_payload_codec_thread_pool
         | 
| 41 | 
            +
                      if !Fiber.current_scheduler && payload_codec && !@workflow_payload_codec_thread_pool
         | 
| 42 | 
            +
                        raise ArgumentError, 'Must have workflow payload codec thread pool if providing codec and not using fibers'
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                      # If there is a payload codec, we need to build encoding and decoding visitors
         | 
| 46 | 
            +
                      if payload_codec
         | 
| 47 | 
            +
                        @payload_encoding_visitor = Api::PayloadVisitor.new(skip_search_attributes: true) do |payload_or_payloads|
         | 
| 48 | 
            +
                          apply_codec_on_payload_visit(payload_or_payloads) { |payloads| payload_codec.encode(payloads) }
         | 
| 49 | 
            +
                        end
         | 
| 50 | 
            +
                        @payload_decoding_visitor = Api::PayloadVisitor.new(skip_search_attributes: true) do |payload_or_payloads|
         | 
| 51 | 
            +
                          apply_codec_on_payload_visit(payload_or_payloads) { |payloads| payload_codec.decode(payloads) }
         | 
| 52 | 
            +
                        end
         | 
| 53 | 
            +
                      end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                      @state = State.new(
         | 
| 56 | 
            +
                        workflow_definitions:,
         | 
| 57 | 
            +
                        bridge_worker:,
         | 
| 58 | 
            +
                        logger: worker.options.logger,
         | 
| 59 | 
            +
                        metric_meter: worker.options.client.connection.options.runtime.metric_meter,
         | 
| 60 | 
            +
                        data_converter: worker.options.client.data_converter,
         | 
| 61 | 
            +
                        deadlock_timeout: worker.options.debug_mode ? nil : 2.0,
         | 
| 62 | 
            +
                        # TODO(cretz): Make this more performant for the default set?
         | 
| 63 | 
            +
                        illegal_calls: WorkflowInstance::IllegalCallTracer.frozen_validated_illegal_calls(
         | 
| 64 | 
            +
                          worker.options.illegal_workflow_calls || {}
         | 
| 65 | 
            +
                        ),
         | 
| 66 | 
            +
                        namespace: worker.options.client.namespace,
         | 
| 67 | 
            +
                        task_queue: worker.options.task_queue,
         | 
| 68 | 
            +
                        disable_eager_activity_execution: worker.options.disable_eager_activity_execution,
         | 
| 69 | 
            +
                        workflow_interceptors: worker._workflow_interceptors,
         | 
| 70 | 
            +
                        workflow_failure_exception_types: worker.options.workflow_failure_exception_types.map do |t|
         | 
| 71 | 
            +
                          unless t.is_a?(Class) && t < Exception
         | 
| 72 | 
            +
                            raise ArgumentError, 'All failure types must classes inheriting Exception'
         | 
| 73 | 
            +
                          end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                          t
         | 
| 76 | 
            +
                        end.freeze
         | 
| 77 | 
            +
                      )
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                      # Validate worker
         | 
| 80 | 
            +
                      @executor._validate_worker(worker, @state)
         | 
| 81 | 
            +
                    end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    def handle_activation(runner:, activation:, decoded:)
         | 
| 84 | 
            +
                      # Encode in background if not encoded but it needs to be
         | 
| 85 | 
            +
                      if @payload_encoding_visitor && !decoded
         | 
| 86 | 
            +
                        if Fiber.current_scheduler
         | 
| 87 | 
            +
                          Fiber.schedule { decode_activation(runner, activation) }
         | 
| 88 | 
            +
                        else
         | 
| 89 | 
            +
                          @workflow_payload_codec_thread_pool.execute { decode_activation(runner, activation) }
         | 
| 90 | 
            +
                        end
         | 
| 91 | 
            +
                      else
         | 
| 92 | 
            +
                        @executor._activate(activation, @state) do |activation_completion|
         | 
| 93 | 
            +
                          runner.apply_workflow_activation_complete(workflow_worker: self, activation_completion:, encoded: false)
         | 
| 94 | 
            +
                        end
         | 
| 95 | 
            +
                      end
         | 
| 96 | 
            +
                    rescue Exception => e # rubocop:disable Lint/RescueException
         | 
| 97 | 
            +
                      # Should never happen, executors are expected to trap things
         | 
| 98 | 
            +
                      @state.logger.error("Failed issuing activation on workflow run ID: #{activation.run_id}")
         | 
| 99 | 
            +
                      @state.logger.error(e)
         | 
| 100 | 
            +
                    end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    def handle_activation_complete(runner:, activation_completion:, encoded:, completion_complete_queue:)
         | 
| 103 | 
            +
                      if @payload_encoding_visitor && !encoded
         | 
| 104 | 
            +
                        if Fiber.current_scheduler
         | 
| 105 | 
            +
                          Fiber.schedule { encode_activation_completion(runner, activation_completion) }
         | 
| 106 | 
            +
                        else
         | 
| 107 | 
            +
                          @workflow_payload_codec_thread_pool.execute do
         | 
| 108 | 
            +
                            encode_activation_completion(runner, activation_completion)
         | 
| 109 | 
            +
                          end
         | 
| 110 | 
            +
                        end
         | 
| 111 | 
            +
                      else
         | 
| 112 | 
            +
                        @state.bridge_worker.async_complete_workflow_activation(
         | 
| 113 | 
            +
                          activation_completion.run_id, activation_completion.to_proto, completion_complete_queue
         | 
| 114 | 
            +
                        )
         | 
| 115 | 
            +
                      end
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                    def on_shutdown_complete
         | 
| 119 | 
            +
                      @state.evict_all
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                    private
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                    def decode_activation(runner, activation)
         | 
| 125 | 
            +
                      @payload_decoding_visitor.run(activation)
         | 
| 126 | 
            +
                      runner.apply_workflow_activation_decoded(workflow_worker: self, activation:)
         | 
| 127 | 
            +
                    end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                    def encode_activation_completion(runner, activation_completion)
         | 
| 130 | 
            +
                      @payload_encoding_visitor.run(activation_completion)
         | 
| 131 | 
            +
                      runner.apply_workflow_activation_complete(workflow_worker: self, activation_completion:, encoded: true)
         | 
| 132 | 
            +
                    end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                    def apply_codec_on_payload_visit(payload_or_payloads, &)
         | 
| 135 | 
            +
                      case payload_or_payloads
         | 
| 136 | 
            +
                      when Temporalio::Api::Common::V1::Payload
         | 
| 137 | 
            +
                        new_payloads = yield [payload_or_payloads]
         | 
| 138 | 
            +
                        payload_or_payloads.metadata = new_payloads.first.metadata
         | 
| 139 | 
            +
                        payload_or_payloads.data = new_payloads.first.data
         | 
| 140 | 
            +
                      when Enumerable
         | 
| 141 | 
            +
                        payload_or_payloads.replace(yield payload_or_payloads) # steep:ignore
         | 
| 142 | 
            +
                      else
         | 
| 143 | 
            +
                        raise 'Unrecognized visitor type'
         | 
| 144 | 
            +
                      end
         | 
| 145 | 
            +
                    end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                    class State
         | 
| 148 | 
            +
                      attr_reader :workflow_definitions, :bridge_worker, :logger, :metric_meter, :data_converter, :deadlock_timeout,
         | 
| 149 | 
            +
                                  :illegal_calls, :namespace, :task_queue, :disable_eager_activity_execution,
         | 
| 150 | 
            +
                                  :workflow_interceptors, :workflow_failure_exception_types
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                      def initialize(
         | 
| 153 | 
            +
                        workflow_definitions:, bridge_worker:, logger:, metric_meter:, data_converter:, deadlock_timeout:,
         | 
| 154 | 
            +
                        illegal_calls:, namespace:, task_queue:, disable_eager_activity_execution:,
         | 
| 155 | 
            +
                        workflow_interceptors:, workflow_failure_exception_types:
         | 
| 156 | 
            +
                      )
         | 
| 157 | 
            +
                        @workflow_definitions = workflow_definitions
         | 
| 158 | 
            +
                        @bridge_worker = bridge_worker
         | 
| 159 | 
            +
                        @logger = logger
         | 
| 160 | 
            +
                        @metric_meter = metric_meter
         | 
| 161 | 
            +
                        @data_converter = data_converter
         | 
| 162 | 
            +
                        @deadlock_timeout = deadlock_timeout
         | 
| 163 | 
            +
                        @illegal_calls = illegal_calls
         | 
| 164 | 
            +
                        @namespace = namespace
         | 
| 165 | 
            +
                        @task_queue = task_queue
         | 
| 166 | 
            +
                        @disable_eager_activity_execution = disable_eager_activity_execution
         | 
| 167 | 
            +
                        @workflow_interceptors = workflow_interceptors
         | 
| 168 | 
            +
                        @workflow_failure_exception_types = workflow_failure_exception_types
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                        @running_workflows = {}
         | 
| 171 | 
            +
                        @running_workflows_mutex = Mutex.new
         | 
| 172 | 
            +
                      end
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                      # This can never be called at the same time for the same run ID on the same state object
         | 
| 175 | 
            +
                      def get_or_create_running_workflow(run_id, &)
         | 
| 176 | 
            +
                        instance = @running_workflows_mutex.synchronize { @running_workflows[run_id] }
         | 
| 177 | 
            +
                        # If instance is not there, we create it out of lock then store it under lock
         | 
| 178 | 
            +
                        unless instance
         | 
| 179 | 
            +
                          instance = yield
         | 
| 180 | 
            +
                          @running_workflows_mutex.synchronize { @running_workflows[run_id] = instance }
         | 
| 181 | 
            +
                        end
         | 
| 182 | 
            +
                        instance
         | 
| 183 | 
            +
                      end
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                      def evict_running_workflow(run_id)
         | 
| 186 | 
            +
                        @running_workflows_mutex.synchronize { @running_workflows.delete(run_id) }
         | 
| 187 | 
            +
                      end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                      def evict_all
         | 
| 190 | 
            +
                        @running_workflows_mutex.synchronize { @running_workflows.clear }
         | 
| 191 | 
            +
                      end
         | 
| 192 | 
            +
                    end
         | 
| 193 | 
            +
                  end
         | 
| 194 | 
            +
                end
         | 
| 195 | 
            +
              end
         | 
| 196 | 
            +
            end
         | 
| @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'temporalio/internal/metric'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Temporalio
         | 
| 6 | 
            +
              # Metric that can be recorded from a metric meter. This is obtained via {Meter.create_metric}. The metric meter is
         | 
| 7 | 
            +
              # obtained via workflow environment, activity context, or from the {Runtime} if in neither of those. This class is
         | 
| 8 | 
            +
              # effectively abstract and will fail if `initialize` is attempted.
         | 
| 9 | 
            +
              class Metric
         | 
| 10 | 
            +
                # @!visibility private
         | 
| 11 | 
            +
                def initialize
         | 
| 12 | 
            +
                  raise NotImplementedError, 'Metric is abstract, implementations override initialize'
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                # Record a value for the metric. For counters, this adds to any existing. For histograms, this records into proper
         | 
| 16 | 
            +
                # buckets. For gauges, this sets the value. The value type must match the expectation.
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                # @param value [Numeric] Value to record. For counters and duration-based histograms, this value cannot be negative.
         | 
| 19 | 
            +
                # @param additional_attributes [Hash{String, Symbol => String, Integer, Float, Boolean}, nil] Additional attributes
         | 
| 20 | 
            +
                #   on this specific record. For better performance for attribute reuse, users are encouraged to use
         | 
| 21 | 
            +
                #   {with_additional_attributes} to make a copy of this metric with those attributes.
         | 
| 22 | 
            +
                def record(value, additional_attributes: nil)
         | 
| 23 | 
            +
                  raise NotImplementedError
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                # Create a copy of this metric but with the given additional attributes. This is more performant than providing
         | 
| 27 | 
            +
                # attributes on each {record} call.
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                # @param additional_attributes [Hash{String, Symbol => String, Integer, Float, Boolean}] Attributes to set on the
         | 
| 30 | 
            +
                #   resulting metric.
         | 
| 31 | 
            +
                # @return [Metric] Copy of this metric with the additional attributes.
         | 
| 32 | 
            +
                def with_additional_attributes(additional_attributes)
         | 
| 33 | 
            +
                  raise NotImplementedError
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # @return [:counter, :histogram, :gauge] Metric type.
         | 
| 37 | 
            +
                def metric_type
         | 
| 38 | 
            +
                  raise NotImplementedError
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                # @return [String] Metric name.
         | 
| 42 | 
            +
                def name
         | 
| 43 | 
            +
                  raise NotImplementedError
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                # @return [String, nil] Metric description.
         | 
| 47 | 
            +
                def description
         | 
| 48 | 
            +
                  raise NotImplementedError
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                # @return [String, nil] Metric unit.
         | 
| 52 | 
            +
                def unit
         | 
| 53 | 
            +
                  raise NotImplementedError
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                # @return [:integer, :float, :duration] Metric value type.
         | 
| 57 | 
            +
                def value_type
         | 
| 58 | 
            +
                  raise NotImplementedError
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                # Meter for creating metrics to record values on. This is obtained via workflow environment, activity context, or
         | 
| 62 | 
            +
                # from the {Runtime} if in neither of those. This class is effectively abstract and will fail if `initialize` is
         | 
| 63 | 
            +
                # attempted.
         | 
| 64 | 
            +
                class Meter
         | 
| 65 | 
            +
                  # @return [Meter] A no-op instance of {Meter}.
         | 
| 66 | 
            +
                  def self.null
         | 
| 67 | 
            +
                    Internal::Metric::NullMeter.instance
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  # @!visibility private
         | 
| 71 | 
            +
                  def initialize
         | 
| 72 | 
            +
                    raise NotImplementedError, 'Meter is abstract, implementations override initialize'
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  # Create a new metric. Only certain metric types are accepted and only value types can work with certain metric
         | 
| 76 | 
            +
                  # types.
         | 
| 77 | 
            +
                  #
         | 
| 78 | 
            +
                  # @param metric_type [:counter, :histogram, :gauge] Metric type. Counters can only have `:integer` value types,
         | 
| 79 | 
            +
                  #   histograms can have `:integer`, `:float`, or :duration` value types, and gauges can have `:integer` or
         | 
| 80 | 
            +
                  #   `:float` value types.
         | 
| 81 | 
            +
                  # @param name [String] Metric name.
         | 
| 82 | 
            +
                  # @param description [String, nil] Metric description.
         | 
| 83 | 
            +
                  # @param unit [String, nil] Metric unit.
         | 
| 84 | 
            +
                  # @param value_type [:integer, :float, :duration] Metric value type. `:integer` works for all metric types,
         | 
| 85 | 
            +
                  #   `:float` works for `:histogram` and `:gauge` metric types, and `:duration` only works for `:histogram` metric
         | 
| 86 | 
            +
                  #   types.
         | 
| 87 | 
            +
                  # @return [Metric] Created metric.
         | 
| 88 | 
            +
                  def create_metric(
         | 
| 89 | 
            +
                    metric_type,
         | 
| 90 | 
            +
                    name,
         | 
| 91 | 
            +
                    description: nil,
         | 
| 92 | 
            +
                    unit: nil,
         | 
| 93 | 
            +
                    value_type: :integer
         | 
| 94 | 
            +
                  )
         | 
| 95 | 
            +
                    raise NotImplementedError
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  # Create a copy of this meter but with the given additional attributes. This is more performant than providing
         | 
| 99 | 
            +
                  # attributes on each {record} call.
         | 
| 100 | 
            +
                  #
         | 
| 101 | 
            +
                  # @param additional_attributes [Hash{String, Symbol => String, Integer, Float, Boolean}] Attributes to set on the
         | 
| 102 | 
            +
                  #   resulting meter.
         | 
| 103 | 
            +
                  # @return [Meter] Copy of this meter with the additional attributes.
         | 
| 104 | 
            +
                  def with_additional_attributes(additional_attributes)
         | 
| 105 | 
            +
                    raise NotImplementedError
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
              end
         | 
| 109 | 
            +
            end
         | 
| @@ -3,6 +3,14 @@ | |
| 3 3 | 
             
            require 'temporalio/internal/proto_utils'
         | 
| 4 4 |  | 
| 5 5 | 
             
            module Temporalio
         | 
| 6 | 
            +
              RetryPolicy = Data.define(
         | 
| 7 | 
            +
                :initial_interval,
         | 
| 8 | 
            +
                :backoff_coefficient,
         | 
| 9 | 
            +
                :max_interval,
         | 
| 10 | 
            +
                :max_attempts,
         | 
| 11 | 
            +
                :non_retryable_error_types
         | 
| 12 | 
            +
              )
         | 
| 13 | 
            +
             | 
| 6 14 | 
             
              # Options for retrying workflows and activities.
         | 
| 7 15 | 
             
              #
         | 
| 8 16 | 
             
              # @!attribute initial_interval
         | 
| @@ -15,24 +23,39 @@ module Temporalio | |
| 15 23 | 
             
              #   @return [Integer] Maximum number of attempts. If `0`, the default, there is no maximum.
         | 
| 16 24 | 
             
              # @!attribute non_retryable_error_types
         | 
| 17 25 | 
             
              #   @return [Array<String>, nil] List of error types that are not retryable.
         | 
| 18 | 
            -
              RetryPolicy | 
| 19 | 
            -
                 | 
| 20 | 
            -
                 | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
                   | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 26 | 
            +
              class RetryPolicy
         | 
| 27 | 
            +
                # @!visibility private
         | 
| 28 | 
            +
                def self._from_proto(raw_policy)
         | 
| 29 | 
            +
                  RetryPolicy.new(
         | 
| 30 | 
            +
                    initial_interval: Internal::ProtoUtils.duration_to_seconds(raw_policy.initial_interval) || raise, # Never nil
         | 
| 31 | 
            +
                    backoff_coefficient: raw_policy.backoff_coefficient,
         | 
| 32 | 
            +
                    max_interval: Internal::ProtoUtils.duration_to_seconds(raw_policy.maximum_interval),
         | 
| 33 | 
            +
                    max_attempts: raw_policy.maximum_attempts,
         | 
| 34 | 
            +
                    non_retryable_error_types: raw_policy.non_retryable_error_types&.to_a
         | 
| 35 | 
            +
                  )
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                # Create retry policy.
         | 
| 39 | 
            +
                #
         | 
| 40 | 
            +
                # @param initial_interval [Float] Backoff interval in seconds for the first retry. Default 1.0.
         | 
| 41 | 
            +
                # @param backoff_coefficient [Float] Coefficient to multiply previous backoff interval by to get new interval.
         | 
| 42 | 
            +
                #   Default 2.0.
         | 
| 43 | 
            +
                # @param max_interval [Float, nil] Maximum backoff interval in seconds between retries. Default 100x
         | 
| 44 | 
            +
                #   `initial_interval`.
         | 
| 45 | 
            +
                # @param max_attempts [Integer] Maximum number of attempts. If `0`, the default, there is no maximum.
         | 
| 46 | 
            +
                # @param non_retryable_error_types [Array<String>, nil] List of error types that are not retryable.
         | 
| 47 | 
            +
                def initialize(
         | 
| 48 | 
            +
                  initial_interval: 1.0,
         | 
| 49 | 
            +
                  backoff_coefficient: 2.0,
         | 
| 50 | 
            +
                  max_interval: nil,
         | 
| 51 | 
            +
                  max_attempts: 0,
         | 
| 52 | 
            +
                  non_retryable_error_types: nil
         | 
| 53 | 
            +
                )
         | 
| 30 54 | 
             
                  super
         | 
| 31 55 | 
             
                end
         | 
| 32 56 |  | 
| 33 57 | 
             
                # @!visibility private
         | 
| 34 | 
            -
                def  | 
| 35 | 
            -
                  # @type self: RetryPolicy
         | 
| 58 | 
            +
                def _to_proto
         | 
| 36 59 | 
             
                  raise 'Initial interval cannot be negative' if initial_interval.negative?
         | 
| 37 60 | 
             
                  raise 'Backoff coefficient cannot be less than 1' if backoff_coefficient < 1
         | 
| 38 61 | 
             
                  raise 'Max interval cannot be negative' if max_interval&.negative?
         | 
    
        data/lib/temporalio/runtime.rb
    CHANGED
    
    | @@ -1,6 +1,9 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'temporalio/internal/bridge'
         | 
| 3 4 | 
             
            require 'temporalio/internal/bridge/runtime'
         | 
| 5 | 
            +
            require 'temporalio/internal/metric'
         | 
| 6 | 
            +
            require 'temporalio/metric'
         | 
| 4 7 |  | 
| 5 8 | 
             
            module Temporalio
         | 
| 6 9 | 
             
              # Runtime for Temporal Ruby SDK.
         | 
| @@ -9,6 +12,11 @@ module Temporalio | |
| 9 12 | 
             
              # before any clients are created, and set it via {default=}. Every time a new runtime is created, a new internal Rust
         | 
| 10 13 | 
             
              # thread pool is created.
         | 
| 11 14 | 
             
              class Runtime
         | 
| 15 | 
            +
                TelemetryOptions = Data.define(
         | 
| 16 | 
            +
                  :logging,
         | 
| 17 | 
            +
                  :metrics
         | 
| 18 | 
            +
                )
         | 
| 19 | 
            +
             | 
| 12 20 | 
             
                # Telemetry options for the runtime.
         | 
| 13 21 | 
             
                #
         | 
| 14 22 | 
             
                # @!attribute logging
         | 
| @@ -16,15 +24,13 @@ module Temporalio | |
| 16 24 | 
             
                #     to nil to disable logging.
         | 
| 17 25 | 
             
                # @!attribute metrics
         | 
| 18 26 | 
             
                #   @return [MetricsOptions, nil] Metrics options.
         | 
| 19 | 
            -
                TelemetryOptions | 
| 20 | 
            -
                   | 
| 21 | 
            -
                   | 
| 22 | 
            -
                   | 
| 23 | 
            -
             | 
| 24 | 
            -
                  #  | 
| 25 | 
            -
                  def initialize( | 
| 26 | 
            -
                    # @type var kwargs: untyped
         | 
| 27 | 
            -
                    kwargs[:logging] = LoggingOptions.new unless kwargs.key?(:logging)
         | 
| 27 | 
            +
                class TelemetryOptions
         | 
| 28 | 
            +
                  # Create telemetry options.
         | 
| 29 | 
            +
                  #
         | 
| 30 | 
            +
                  # @param logging [LoggingOptions, nil] Logging options, default is new {LoggingOptions} with no parameters. Can be
         | 
| 31 | 
            +
                  #   set to nil to disable logging.
         | 
| 32 | 
            +
                  # @param metrics [MetricsOptions, nil] Metrics options.
         | 
| 33 | 
            +
                  def initialize(logging: LoggingOptions.new, metrics: nil)
         | 
| 28 34 | 
             
                    super
         | 
| 29 35 | 
             
                  end
         | 
| 30 36 |  | 
| @@ -38,20 +44,21 @@ module Temporalio | |
| 38 44 | 
             
                  end
         | 
| 39 45 | 
             
                end
         | 
| 40 46 |  | 
| 47 | 
            +
                LoggingOptions = Data.define(
         | 
| 48 | 
            +
                  :log_filter
         | 
| 49 | 
            +
                  # TODO(cretz): forward_to
         | 
| 50 | 
            +
                )
         | 
| 51 | 
            +
             | 
| 41 52 | 
             
                # Logging options for runtime telemetry.
         | 
| 42 53 | 
             
                #
         | 
| 43 54 | 
             
                # @!attribute log_filter
         | 
| 44 55 | 
             
                #   @return [LoggingFilterOptions, String] Logging filter for Core, default is new {LoggingFilterOptions} with no
         | 
| 45 56 | 
             
                #     parameters.
         | 
| 46 | 
            -
                LoggingOptions | 
| 47 | 
            -
                   | 
| 48 | 
            -
                  # | 
| 49 | 
            -
                   | 
| 50 | 
            -
             | 
| 51 | 
            -
                  # @!visibility private
         | 
| 52 | 
            -
                  def initialize(**kwargs)
         | 
| 53 | 
            -
                    # @type var kwargs: untyped
         | 
| 54 | 
            -
                    kwargs[:log_filter] = LoggingFilterOptions.new unless kwargs.key?(:log_filter)
         | 
| 57 | 
            +
                class LoggingOptions
         | 
| 58 | 
            +
                  # Create logging options
         | 
| 59 | 
            +
                  #
         | 
| 60 | 
            +
                  # @param log_filter [LoggingFilterOptions, String] Logging filter for Core.
         | 
| 61 | 
            +
                  def initialize(log_filter: LoggingFilterOptions.new)
         | 
| 55 62 | 
             
                    super
         | 
| 56 63 | 
             
                  end
         | 
| 57 64 |  | 
| @@ -70,22 +77,23 @@ module Temporalio | |
| 70 77 | 
             
                  end
         | 
| 71 78 | 
             
                end
         | 
| 72 79 |  | 
| 80 | 
            +
                LoggingFilterOptions = Data.define(
         | 
| 81 | 
            +
                  :core_level,
         | 
| 82 | 
            +
                  :other_level
         | 
| 83 | 
            +
                )
         | 
| 84 | 
            +
             | 
| 73 85 | 
             
                # Logging filter options for Core.
         | 
| 74 86 | 
             
                #
         | 
| 75 87 | 
             
                # @!attribute core_level
         | 
| 76 | 
            -
                #   @return ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'] Log level for Core log messages | 
| 88 | 
            +
                #   @return ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'] Log level for Core log messages.
         | 
| 77 89 | 
             
                # @!attribute other_level
         | 
| 78 | 
            -
                #   @return ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'] Log level for other Rust log messages | 
| 79 | 
            -
                LoggingFilterOptions | 
| 80 | 
            -
                   | 
| 81 | 
            -
                   | 
| 82 | 
            -
                   | 
| 83 | 
            -
             | 
| 84 | 
            -
                   | 
| 85 | 
            -
                  def initialize(**kwargs)
         | 
| 86 | 
            -
                    # @type var kwargs: untyped
         | 
| 87 | 
            -
                    kwargs[:core_level] = 'WARN' unless kwargs.key?(:core_level)
         | 
| 88 | 
            -
                    kwargs[:other_level] = 'ERROR' unless kwargs.key?(:other_level)
         | 
| 90 | 
            +
                #   @return ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'] Log level for other Rust log messages.
         | 
| 91 | 
            +
                class LoggingFilterOptions
         | 
| 92 | 
            +
                  # Create logging filter options.
         | 
| 93 | 
            +
                  #
         | 
| 94 | 
            +
                  # @param core_level ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'] Log level for Core log messages.
         | 
| 95 | 
            +
                  # @!attribute other_level ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'] Log level for other Rust log messages.
         | 
| 96 | 
            +
                  def initialize(core_level: 'WARN', other_level: 'ERROR')
         | 
| 89 97 | 
             
                    super
         | 
| 90 98 | 
             
                  end
         | 
| 91 99 |  | 
| @@ -96,6 +104,14 @@ module Temporalio | |
| 96 104 | 
             
                  end
         | 
| 97 105 | 
             
                end
         | 
| 98 106 |  | 
| 107 | 
            +
                MetricsOptions = Data.define(
         | 
| 108 | 
            +
                  :opentelemetry,
         | 
| 109 | 
            +
                  :prometheus,
         | 
| 110 | 
            +
                  :attach_service_name,
         | 
| 111 | 
            +
                  :global_tags,
         | 
| 112 | 
            +
                  :metric_prefix
         | 
| 113 | 
            +
                )
         | 
| 114 | 
            +
             | 
| 99 115 | 
             
                # Metrics options for runtime telemetry. Either {opentelemetry} or {prometheus} required, but not both.
         | 
| 100 116 | 
             
                #
         | 
| 101 117 | 
             
                # @!attribute opentelemetry
         | 
| @@ -105,23 +121,28 @@ module Temporalio | |
| 105 121 | 
             
                #   @return [PrometheusMetricsOptions, nil] Prometheus options if using Prometheus. This is mutually exclusive with
         | 
| 106 122 | 
             
                #     +opentelemetry+.
         | 
| 107 123 | 
             
                # @!attribute attach_service_name
         | 
| 108 | 
            -
                #   @return [Boolean] Whether to put the service_name on every metric | 
| 124 | 
            +
                #   @return [Boolean] Whether to put the service_name on every metric.
         | 
| 109 125 | 
             
                # @!attribute global_tags
         | 
| 110 126 | 
             
                #   @return [Hash<String, String>, nil] Resource tags to be applied to all metrics.
         | 
| 111 127 | 
             
                # @!attribute metric_prefix
         | 
| 112 | 
            -
                #   @return [String, nil] Prefix to put on every Temporal metric. If unset, defaults to  | 
| 113 | 
            -
                MetricsOptions | 
| 114 | 
            -
                   | 
| 115 | 
            -
                   | 
| 116 | 
            -
                   | 
| 117 | 
            -
                   | 
| 118 | 
            -
                   | 
| 119 | 
            -
                   | 
| 120 | 
            -
             | 
| 121 | 
            -
                  #  | 
| 122 | 
            -
                   | 
| 123 | 
            -
             | 
| 124 | 
            -
                     | 
| 128 | 
            +
                #   @return [String, nil] Prefix to put on every Temporal metric. If unset, defaults to `temporal_`.
         | 
| 129 | 
            +
                class MetricsOptions
         | 
| 130 | 
            +
                  # Create metrics options. Either `opentelemetry` or `prometheus` required, but not both.
         | 
| 131 | 
            +
                  #
         | 
| 132 | 
            +
                  # @param opentelemetry [OpenTelemetryMetricsOptions, nil] OpenTelemetry options if using OpenTelemetry. This is
         | 
| 133 | 
            +
                  #   mutually exclusive with `prometheus`.
         | 
| 134 | 
            +
                  # @param prometheus [PrometheusMetricsOptions, nil] Prometheus options if using Prometheus. This is mutually
         | 
| 135 | 
            +
                  #   exclusive with `opentelemetry`.
         | 
| 136 | 
            +
                  # @param attach_service_name [Boolean] Whether to put the service_name on every metric.
         | 
| 137 | 
            +
                  # @param global_tags [Hash<String, String>, nil] Resource tags to be applied to all metrics.
         | 
| 138 | 
            +
                  # @param metric_prefix [String, nil] Prefix to put on every Temporal metric. If unset, defaults to `temporal_`.
         | 
| 139 | 
            +
                  def initialize(
         | 
| 140 | 
            +
                    opentelemetry: nil,
         | 
| 141 | 
            +
                    prometheus: nil,
         | 
| 142 | 
            +
                    attach_service_name: true,
         | 
| 143 | 
            +
                    global_tags: nil,
         | 
| 144 | 
            +
                    metric_prefix: nil
         | 
| 145 | 
            +
                  )
         | 
| 125 146 | 
             
                    super
         | 
| 126 147 | 
             
                  end
         | 
| 127 148 |  | 
| @@ -138,6 +159,14 @@ module Temporalio | |
| 138 159 | 
             
                  end
         | 
| 139 160 | 
             
                end
         | 
| 140 161 |  | 
| 162 | 
            +
                OpenTelemetryMetricsOptions = Data.define(
         | 
| 163 | 
            +
                  :url,
         | 
| 164 | 
            +
                  :headers,
         | 
| 165 | 
            +
                  :metric_periodicity,
         | 
| 166 | 
            +
                  :metric_temporality,
         | 
| 167 | 
            +
                  :durations_as_seconds
         | 
| 168 | 
            +
                )
         | 
| 169 | 
            +
             | 
| 141 170 | 
             
                # Options for exporting metrics to OpenTelemetry.
         | 
| 142 171 | 
             
                #
         | 
| 143 172 | 
             
                # @!attribute url
         | 
| @@ -152,25 +181,28 @@ module Temporalio | |
| 152 181 | 
             
                # @!attribute durations_as_seconds
         | 
| 153 182 | 
             
                #   @return [Boolean] Whether to use float seconds instead of integer milliseconds for durations, default is
         | 
| 154 183 | 
             
                #     +false+.
         | 
| 155 | 
            -
                OpenTelemetryMetricsOptions | 
| 156 | 
            -
                  :url,
         | 
| 157 | 
            -
                  :headers,
         | 
| 158 | 
            -
                  :metric_periodicity,
         | 
| 159 | 
            -
                  :metric_temporality,
         | 
| 160 | 
            -
                  :durations_as_seconds,
         | 
| 161 | 
            -
                  keyword_init: true
         | 
| 162 | 
            -
                ) do
         | 
| 184 | 
            +
                class OpenTelemetryMetricsOptions
         | 
| 163 185 | 
             
                  # OpenTelemetry metric temporality.
         | 
| 164 | 
            -
                  module MetricTemporality | 
| 186 | 
            +
                  module MetricTemporality
         | 
| 165 187 | 
             
                    CUMULATIVE = 1
         | 
| 166 188 | 
             
                    DELTA = 2
         | 
| 167 189 | 
             
                  end
         | 
| 168 190 |  | 
| 169 | 
            -
                  #  | 
| 170 | 
            -
                   | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 191 | 
            +
                  # Create OpenTelemetry options.
         | 
| 192 | 
            +
                  #
         | 
| 193 | 
            +
                  # @param url [String] URL for OpenTelemetry endpoint.
         | 
| 194 | 
            +
                  # @param headers [Hash<String, String>, nil] Headers for OpenTelemetry endpoint.
         | 
| 195 | 
            +
                  # @param metric_periodicity [Float, nil] How frequently metrics should be exported, unset uses internal default.
         | 
| 196 | 
            +
                  # @param metric_temporality [MetricTemporality] How frequently metrics should be exported.
         | 
| 197 | 
            +
                  # @param durations_as_seconds [Boolean] Whether to use float seconds instead of integer milliseconds for
         | 
| 198 | 
            +
                  #   durations.
         | 
| 199 | 
            +
                  def initialize(
         | 
| 200 | 
            +
                    url:,
         | 
| 201 | 
            +
                    headers: nil,
         | 
| 202 | 
            +
                    metric_periodicity: nil,
         | 
| 203 | 
            +
                    metric_temporality: MetricTemporality::CUMULATIVE,
         | 
| 204 | 
            +
                    durations_as_seconds: false
         | 
| 205 | 
            +
                  )
         | 
| 174 206 | 
             
                    super
         | 
| 175 207 | 
             
                  end
         | 
| 176 208 |  | 
| @@ -191,30 +223,37 @@ module Temporalio | |
| 191 223 | 
             
                  end
         | 
| 192 224 | 
             
                end
         | 
| 193 225 |  | 
| 226 | 
            +
                PrometheusMetricsOptions = Data.define(
         | 
| 227 | 
            +
                  :bind_address,
         | 
| 228 | 
            +
                  :counters_total_suffix,
         | 
| 229 | 
            +
                  :unit_suffix,
         | 
| 230 | 
            +
                  :durations_as_seconds
         | 
| 231 | 
            +
                )
         | 
| 232 | 
            +
             | 
| 194 233 | 
             
                # Options for exporting metrics to Prometheus.
         | 
| 195 234 | 
             
                #
         | 
| 196 235 | 
             
                # @!attribute bind_address
         | 
| 197 236 | 
             
                #   @return [String] Address to bind to for Prometheus endpoint.
         | 
| 198 237 | 
             
                # @!attribute counters_total_suffix
         | 
| 199 | 
            -
                #   @return [Boolean] If  | 
| 238 | 
            +
                #   @return [Boolean] If `true`, all counters will include a `_total` suffix.
         | 
| 200 239 | 
             
                # @!attribute unit_suffix
         | 
| 201 | 
            -
                #   @return [Boolean] If  | 
| 240 | 
            +
                #   @return [Boolean] If `true`, all histograms will include the unit in their name as a suffix.
         | 
| 202 241 | 
             
                # @!attribute durations_as_seconds
         | 
| 203 | 
            -
                #   @return [Boolean] Whether to use float seconds instead of integer milliseconds for durations | 
| 204 | 
            -
                 | 
| 205 | 
            -
             | 
| 206 | 
            -
                   | 
| 207 | 
            -
                   | 
| 208 | 
            -
                   | 
| 209 | 
            -
                   | 
| 210 | 
            -
                   | 
| 211 | 
            -
             | 
| 212 | 
            -
                   | 
| 213 | 
            -
             | 
| 214 | 
            -
                     | 
| 215 | 
            -
                     | 
| 216 | 
            -
                     | 
| 217 | 
            -
             | 
| 242 | 
            +
                #   @return [Boolean] Whether to use float seconds instead of integer milliseconds for durations.
         | 
| 243 | 
            +
                class PrometheusMetricsOptions
         | 
| 244 | 
            +
                  # Create Prometheus options.
         | 
| 245 | 
            +
                  #
         | 
| 246 | 
            +
                  # @param bind_address [String] Address to bind to for Prometheus endpoint.
         | 
| 247 | 
            +
                  # @param counters_total_suffix [Boolean] If `true`, all counters will include a `_total` suffix.
         | 
| 248 | 
            +
                  # @param unit_suffix [Boolean] If `true`, all histograms will include the unit in their name as a suffix.
         | 
| 249 | 
            +
                  # @param durations_as_seconds [Boolean] Whether to use float seconds instead of integer milliseconds for
         | 
| 250 | 
            +
                  #   durations.
         | 
| 251 | 
            +
                  def initialize(
         | 
| 252 | 
            +
                    bind_address:,
         | 
| 253 | 
            +
                    counters_total_suffix: false,
         | 
| 254 | 
            +
                    unit_suffix: false,
         | 
| 255 | 
            +
                    durations_as_seconds: false
         | 
| 256 | 
            +
                  )
         | 
| 218 257 | 
             
                    super
         | 
| 219 258 | 
             
                  end
         | 
| 220 259 |  | 
| @@ -248,6 +287,9 @@ module Temporalio | |
| 248 287 | 
             
                  @default = runtime
         | 
| 249 288 | 
             
                end
         | 
| 250 289 |  | 
| 290 | 
            +
                # @return [Metric::Meter] Metric meter that can create and record metric values.
         | 
| 291 | 
            +
                attr_reader :metric_meter
         | 
| 292 | 
            +
             | 
| 251 293 | 
             
                # Create new Runtime. For most users, this should only be done once globally. In addition to creating a Rust thread
         | 
| 252 294 | 
             
                # pool, this also consumes a Ruby thread for its lifetime.
         | 
| 253 295 | 
             
                #
         | 
| @@ -256,6 +298,7 @@ module Temporalio | |
| 256 298 | 
             
                  @core_runtime = Internal::Bridge::Runtime.new(
         | 
| 257 299 | 
             
                    Internal::Bridge::Runtime::Options.new(telemetry: telemetry._to_bridge)
         | 
| 258 300 | 
             
                  )
         | 
| 301 | 
            +
                  @metric_meter = Internal::Metric::Meter.create_from_runtime(self) || Metric::Meter.null
         | 
| 259 302 | 
             
                  # We need a thread to run the command loop
         | 
| 260 303 | 
             
                  # TODO(cretz): Is this something users should be concerned about or need control over?
         | 
| 261 304 | 
             
                  Thread.new do
         |