temporalio 0.4.0-aarch64-linux-musl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +2 -0
  3. data/Gemfile +27 -0
  4. data/Rakefile +101 -0
  5. data/lib/temporalio/activity/complete_async_error.rb +11 -0
  6. data/lib/temporalio/activity/context.rb +123 -0
  7. data/lib/temporalio/activity/definition.rb +192 -0
  8. data/lib/temporalio/activity/info.rb +67 -0
  9. data/lib/temporalio/activity.rb +12 -0
  10. data/lib/temporalio/api/activity/v1/message.rb +25 -0
  11. data/lib/temporalio/api/batch/v1/message.rb +36 -0
  12. data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
  13. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +126 -0
  14. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +25 -0
  15. data/lib/temporalio/api/cloud/cloudservice.rb +3 -0
  16. data/lib/temporalio/api/cloud/identity/v1/message.rb +41 -0
  17. data/lib/temporalio/api/cloud/namespace/v1/message.rb +42 -0
  18. data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
  19. data/lib/temporalio/api/cloud/operation/v1/message.rb +28 -0
  20. data/lib/temporalio/api/cloud/region/v1/message.rb +24 -0
  21. data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
  22. data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
  23. data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
  24. data/lib/temporalio/api/command/v1/message.rb +46 -0
  25. data/lib/temporalio/api/common/v1/grpc_status.rb +23 -0
  26. data/lib/temporalio/api/common/v1/message.rb +48 -0
  27. data/lib/temporalio/api/deployment/v1/message.rb +38 -0
  28. data/lib/temporalio/api/enums/v1/batch_operation.rb +22 -0
  29. data/lib/temporalio/api/enums/v1/command_type.rb +21 -0
  30. data/lib/temporalio/api/enums/v1/common.rb +26 -0
  31. data/lib/temporalio/api/enums/v1/deployment.rb +23 -0
  32. data/lib/temporalio/api/enums/v1/event_type.rb +21 -0
  33. data/lib/temporalio/api/enums/v1/failed_cause.rb +26 -0
  34. data/lib/temporalio/api/enums/v1/namespace.rb +23 -0
  35. data/lib/temporalio/api/enums/v1/nexus.rb +21 -0
  36. data/lib/temporalio/api/enums/v1/query.rb +22 -0
  37. data/lib/temporalio/api/enums/v1/reset.rb +23 -0
  38. data/lib/temporalio/api/enums/v1/schedule.rb +21 -0
  39. data/lib/temporalio/api/enums/v1/task_queue.rb +25 -0
  40. data/lib/temporalio/api/enums/v1/update.rb +22 -0
  41. data/lib/temporalio/api/enums/v1/workflow.rb +31 -0
  42. data/lib/temporalio/api/errordetails/v1/message.rb +44 -0
  43. data/lib/temporalio/api/export/v1/message.rb +24 -0
  44. data/lib/temporalio/api/failure/v1/message.rb +37 -0
  45. data/lib/temporalio/api/filter/v1/message.rb +27 -0
  46. data/lib/temporalio/api/history/v1/message.rb +92 -0
  47. data/lib/temporalio/api/namespace/v1/message.rb +31 -0
  48. data/lib/temporalio/api/nexus/v1/message.rb +41 -0
  49. data/lib/temporalio/api/operatorservice/v1/request_response.rb +49 -0
  50. data/lib/temporalio/api/operatorservice/v1/service.rb +23 -0
  51. data/lib/temporalio/api/operatorservice.rb +3 -0
  52. data/lib/temporalio/api/payload_visitor.rb +1581 -0
  53. data/lib/temporalio/api/protocol/v1/message.rb +23 -0
  54. data/lib/temporalio/api/query/v1/message.rb +28 -0
  55. data/lib/temporalio/api/replication/v1/message.rb +26 -0
  56. data/lib/temporalio/api/schedule/v1/message.rb +43 -0
  57. data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +25 -0
  58. data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +21 -0
  59. data/lib/temporalio/api/sdk/v1/user_metadata.rb +23 -0
  60. data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +23 -0
  61. data/lib/temporalio/api/taskqueue/v1/message.rb +48 -0
  62. data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
  63. data/lib/temporalio/api/testservice/v1/service.rb +23 -0
  64. data/lib/temporalio/api/update/v1/message.rb +33 -0
  65. data/lib/temporalio/api/version/v1/message.rb +26 -0
  66. data/lib/temporalio/api/workflow/v1/message.rb +51 -0
  67. data/lib/temporalio/api/workflowservice/v1/request_response.rb +233 -0
  68. data/lib/temporalio/api/workflowservice/v1/service.rb +23 -0
  69. data/lib/temporalio/api/workflowservice.rb +3 -0
  70. data/lib/temporalio/api.rb +15 -0
  71. data/lib/temporalio/cancellation.rb +170 -0
  72. data/lib/temporalio/client/activity_id_reference.rb +32 -0
  73. data/lib/temporalio/client/async_activity_handle.rb +85 -0
  74. data/lib/temporalio/client/connection/cloud_service.rb +726 -0
  75. data/lib/temporalio/client/connection/operator_service.rb +201 -0
  76. data/lib/temporalio/client/connection/service.rb +42 -0
  77. data/lib/temporalio/client/connection/test_service.rb +111 -0
  78. data/lib/temporalio/client/connection/workflow_service.rb +1251 -0
  79. data/lib/temporalio/client/connection.rb +316 -0
  80. data/lib/temporalio/client/interceptor.rb +455 -0
  81. data/lib/temporalio/client/schedule.rb +991 -0
  82. data/lib/temporalio/client/schedule_handle.rb +126 -0
  83. data/lib/temporalio/client/with_start_workflow_operation.rb +115 -0
  84. data/lib/temporalio/client/workflow_execution.rb +119 -0
  85. data/lib/temporalio/client/workflow_execution_count.rb +36 -0
  86. data/lib/temporalio/client/workflow_execution_status.rb +18 -0
  87. data/lib/temporalio/client/workflow_handle.rb +389 -0
  88. data/lib/temporalio/client/workflow_query_reject_condition.rb +14 -0
  89. data/lib/temporalio/client/workflow_update_handle.rb +65 -0
  90. data/lib/temporalio/client/workflow_update_wait_stage.rb +17 -0
  91. data/lib/temporalio/client.rb +607 -0
  92. data/lib/temporalio/common_enums.rb +41 -0
  93. data/lib/temporalio/contrib/open_telemetry.rb +470 -0
  94. data/lib/temporalio/converters/data_converter.rb +99 -0
  95. data/lib/temporalio/converters/failure_converter.rb +202 -0
  96. data/lib/temporalio/converters/payload_codec.rb +26 -0
  97. data/lib/temporalio/converters/payload_converter/binary_null.rb +34 -0
  98. data/lib/temporalio/converters/payload_converter/binary_plain.rb +35 -0
  99. data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +42 -0
  100. data/lib/temporalio/converters/payload_converter/composite.rb +66 -0
  101. data/lib/temporalio/converters/payload_converter/encoding.rb +35 -0
  102. data/lib/temporalio/converters/payload_converter/json_plain.rb +44 -0
  103. data/lib/temporalio/converters/payload_converter/json_protobuf.rb +41 -0
  104. data/lib/temporalio/converters/payload_converter.rb +71 -0
  105. data/lib/temporalio/converters/raw_value.rb +20 -0
  106. data/lib/temporalio/converters.rb +9 -0
  107. data/lib/temporalio/error/failure.rb +219 -0
  108. data/lib/temporalio/error.rb +156 -0
  109. data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.so +0 -0
  110. data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
  111. data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
  112. data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +34 -0
  113. data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +31 -0
  114. data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +33 -0
  115. data/lib/temporalio/internal/bridge/api/common/common.rb +27 -0
  116. data/lib/temporalio/internal/bridge/api/core_interface.rb +40 -0
  117. data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +27 -0
  118. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
  119. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +56 -0
  120. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +57 -0
  121. data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +31 -0
  122. data/lib/temporalio/internal/bridge/api.rb +3 -0
  123. data/lib/temporalio/internal/bridge/client.rb +95 -0
  124. data/lib/temporalio/internal/bridge/runtime.rb +56 -0
  125. data/lib/temporalio/internal/bridge/testing.rb +69 -0
  126. data/lib/temporalio/internal/bridge/worker.rb +85 -0
  127. data/lib/temporalio/internal/bridge.rb +36 -0
  128. data/lib/temporalio/internal/client/implementation.rb +922 -0
  129. data/lib/temporalio/internal/metric.rb +122 -0
  130. data/lib/temporalio/internal/proto_utils.rb +165 -0
  131. data/lib/temporalio/internal/worker/activity_worker.rb +385 -0
  132. data/lib/temporalio/internal/worker/multi_runner.rb +213 -0
  133. data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
  134. data/lib/temporalio/internal/worker/workflow_instance/context.rb +383 -0
  135. data/lib/temporalio/internal/worker/workflow_instance/details.rb +46 -0
  136. data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
  137. data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
  138. data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
  139. data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
  140. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
  141. data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
  142. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +400 -0
  143. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
  144. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
  145. data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +183 -0
  146. data/lib/temporalio/internal/worker/workflow_instance.rb +774 -0
  147. data/lib/temporalio/internal/worker/workflow_worker.rb +239 -0
  148. data/lib/temporalio/internal.rb +7 -0
  149. data/lib/temporalio/metric.rb +109 -0
  150. data/lib/temporalio/retry_policy.rb +74 -0
  151. data/lib/temporalio/runtime/metric_buffer.rb +94 -0
  152. data/lib/temporalio/runtime.rb +352 -0
  153. data/lib/temporalio/scoped_logger.rb +96 -0
  154. data/lib/temporalio/search_attributes.rb +356 -0
  155. data/lib/temporalio/testing/activity_environment.rb +160 -0
  156. data/lib/temporalio/testing/workflow_environment.rb +406 -0
  157. data/lib/temporalio/testing.rb +10 -0
  158. data/lib/temporalio/version.rb +5 -0
  159. data/lib/temporalio/worker/activity_executor/fiber.rb +49 -0
  160. data/lib/temporalio/worker/activity_executor/thread_pool.rb +46 -0
  161. data/lib/temporalio/worker/activity_executor.rb +55 -0
  162. data/lib/temporalio/worker/interceptor.rb +365 -0
  163. data/lib/temporalio/worker/thread_pool.rb +237 -0
  164. data/lib/temporalio/worker/tuner.rb +189 -0
  165. data/lib/temporalio/worker/workflow_executor/thread_pool.rb +235 -0
  166. data/lib/temporalio/worker/workflow_executor.rb +26 -0
  167. data/lib/temporalio/worker/workflow_replayer.rb +350 -0
  168. data/lib/temporalio/worker.rb +603 -0
  169. data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
  170. data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
  171. data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
  172. data/lib/temporalio/workflow/definition.rb +598 -0
  173. data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
  174. data/lib/temporalio/workflow/future.rb +151 -0
  175. data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
  176. data/lib/temporalio/workflow/info.rb +104 -0
  177. data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
  178. data/lib/temporalio/workflow/update_info.rb +20 -0
  179. data/lib/temporalio/workflow.rb +575 -0
  180. data/lib/temporalio/workflow_history.rb +47 -0
  181. data/lib/temporalio.rb +11 -0
  182. data/temporalio.gemspec +29 -0
  183. metadata +258 -0
@@ -0,0 +1,239 @@
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 self.bridge_workflow_failure_exception_type_options(
37
+ workflow_failure_exception_types:,
38
+ workflow_definitions:
39
+ )
40
+ as_fail = workflow_failure_exception_types.any? do |t|
41
+ t.is_a?(Class) && t >= Workflow::NondeterminismError
42
+ end
43
+ as_fail_for_types = workflow_definitions.values.map do |defn|
44
+ next unless defn.failure_exception_types.any? { |t| t.is_a?(Class) && t >= Workflow::NondeterminismError }
45
+
46
+ # If they tried to do this on a dynamic workflow and haven't already set worker-level option, warn
47
+ unless defn.name || as_fail
48
+ warn('Note, dynamic workflows cannot trap non-determinism errors, so worker-level ' \
49
+ 'workflow_failure_exception_types should be set to capture that if that is the intention')
50
+ end
51
+ defn.name
52
+ end.compact
53
+ [as_fail, as_fail_for_types]
54
+ end
55
+
56
+ def initialize(
57
+ bridge_worker:,
58
+ namespace:,
59
+ task_queue:,
60
+ workflow_definitions:,
61
+ workflow_executor:,
62
+ logger:,
63
+ data_converter:,
64
+ metric_meter:,
65
+ workflow_interceptors:,
66
+ disable_eager_activity_execution:,
67
+ illegal_workflow_calls:,
68
+ workflow_failure_exception_types:,
69
+ workflow_payload_codec_thread_pool:,
70
+ unsafe_workflow_io_enabled:,
71
+ debug_mode:,
72
+ on_eviction: nil
73
+ )
74
+ @executor = workflow_executor
75
+
76
+ payload_codec = data_converter.payload_codec
77
+ @workflow_payload_codec_thread_pool = workflow_payload_codec_thread_pool
78
+ if !Fiber.current_scheduler && payload_codec && !@workflow_payload_codec_thread_pool
79
+ raise ArgumentError, 'Must have workflow payload codec thread pool if providing codec and not using fibers'
80
+ end
81
+
82
+ # If there is a payload codec, we need to build encoding and decoding visitors
83
+ if payload_codec
84
+ @payload_encoding_visitor = Api::PayloadVisitor.new(skip_search_attributes: true) do |payload_or_payloads|
85
+ apply_codec_on_payload_visit(payload_or_payloads) { |payloads| payload_codec.encode(payloads) }
86
+ end
87
+ @payload_decoding_visitor = Api::PayloadVisitor.new(skip_search_attributes: true) do |payload_or_payloads|
88
+ apply_codec_on_payload_visit(payload_or_payloads) { |payloads| payload_codec.decode(payloads) }
89
+ end
90
+ end
91
+
92
+ @state = State.new(
93
+ workflow_definitions:,
94
+ bridge_worker:,
95
+ logger:,
96
+ metric_meter:,
97
+ data_converter:,
98
+ deadlock_timeout: debug_mode ? nil : 2.0,
99
+ # TODO(cretz): Make this more performant for the default set?
100
+ illegal_calls: WorkflowInstance::IllegalCallTracer.frozen_validated_illegal_calls(
101
+ illegal_workflow_calls || {}
102
+ ),
103
+ namespace:,
104
+ task_queue:,
105
+ disable_eager_activity_execution:,
106
+ workflow_interceptors:,
107
+ workflow_failure_exception_types: workflow_failure_exception_types.map do |t|
108
+ unless t.is_a?(Class) && t < Exception
109
+ raise ArgumentError, 'All failure types must classes inheriting Exception'
110
+ end
111
+
112
+ t
113
+ end.freeze,
114
+ unsafe_workflow_io_enabled:
115
+ )
116
+ @state.on_eviction = on_eviction if on_eviction
117
+
118
+ # Validate worker
119
+ @executor._validate_worker(self, @state)
120
+ end
121
+
122
+ def handle_activation(runner:, activation:, decoded:)
123
+ # Encode in background if not encoded but it needs to be
124
+ if @payload_encoding_visitor && !decoded
125
+ if Fiber.current_scheduler
126
+ Fiber.schedule { decode_activation(runner, activation) }
127
+ else
128
+ @workflow_payload_codec_thread_pool.execute { decode_activation(runner, activation) }
129
+ end
130
+ else
131
+ @executor._activate(activation, @state) do |activation_completion|
132
+ runner.apply_workflow_activation_complete(workflow_worker: self, activation_completion:, encoded: false)
133
+ end
134
+ end
135
+ rescue Exception => e # rubocop:disable Lint/RescueException
136
+ # Should never happen, executors are expected to trap things
137
+ @state.logger.error("Failed issuing activation on workflow run ID: #{activation.run_id}")
138
+ @state.logger.error(e)
139
+ end
140
+
141
+ def handle_activation_complete(runner:, activation_completion:, encoded:, completion_complete_queue:)
142
+ if @payload_encoding_visitor && !encoded
143
+ if Fiber.current_scheduler
144
+ Fiber.schedule { encode_activation_completion(runner, activation_completion) }
145
+ else
146
+ @workflow_payload_codec_thread_pool.execute do
147
+ encode_activation_completion(runner, activation_completion)
148
+ end
149
+ end
150
+ else
151
+ @state.bridge_worker.async_complete_workflow_activation(
152
+ activation_completion.run_id, activation_completion.to_proto, completion_complete_queue
153
+ )
154
+ end
155
+ end
156
+
157
+ def on_shutdown_complete
158
+ @state.evict_all
159
+ end
160
+
161
+ private
162
+
163
+ def decode_activation(runner, activation)
164
+ @payload_decoding_visitor.run(activation)
165
+ runner.apply_workflow_activation_decoded(workflow_worker: self, activation:)
166
+ end
167
+
168
+ def encode_activation_completion(runner, activation_completion)
169
+ @payload_encoding_visitor.run(activation_completion)
170
+ runner.apply_workflow_activation_complete(workflow_worker: self, activation_completion:, encoded: true)
171
+ end
172
+
173
+ def apply_codec_on_payload_visit(payload_or_payloads, &)
174
+ case payload_or_payloads
175
+ when Temporalio::Api::Common::V1::Payload
176
+ new_payloads = yield [payload_or_payloads]
177
+ payload_or_payloads.metadata = new_payloads.first.metadata
178
+ payload_or_payloads.data = new_payloads.first.data
179
+ when Enumerable
180
+ payload_or_payloads.replace(yield payload_or_payloads) # steep:ignore
181
+ else
182
+ raise 'Unrecognized visitor type'
183
+ end
184
+ end
185
+
186
+ class State
187
+ attr_reader :workflow_definitions, :bridge_worker, :logger, :metric_meter, :data_converter, :deadlock_timeout,
188
+ :illegal_calls, :namespace, :task_queue, :disable_eager_activity_execution,
189
+ :workflow_interceptors, :workflow_failure_exception_types, :unsafe_workflow_io_enabled
190
+
191
+ attr_writer :on_eviction
192
+
193
+ def initialize(
194
+ workflow_definitions:, bridge_worker:, logger:, metric_meter:, data_converter:, deadlock_timeout:,
195
+ illegal_calls:, namespace:, task_queue:, disable_eager_activity_execution:,
196
+ workflow_interceptors:, workflow_failure_exception_types:, unsafe_workflow_io_enabled:
197
+ )
198
+ @workflow_definitions = workflow_definitions
199
+ @bridge_worker = bridge_worker
200
+ @logger = logger
201
+ @metric_meter = metric_meter
202
+ @data_converter = data_converter
203
+ @deadlock_timeout = deadlock_timeout
204
+ @illegal_calls = illegal_calls
205
+ @namespace = namespace
206
+ @task_queue = task_queue
207
+ @disable_eager_activity_execution = disable_eager_activity_execution
208
+ @workflow_interceptors = workflow_interceptors
209
+ @workflow_failure_exception_types = workflow_failure_exception_types
210
+ @unsafe_workflow_io_enabled = unsafe_workflow_io_enabled
211
+
212
+ @running_workflows = {}
213
+ @running_workflows_mutex = Mutex.new
214
+ end
215
+
216
+ # This can never be called at the same time for the same run ID on the same state object
217
+ def get_or_create_running_workflow(run_id, &)
218
+ instance = @running_workflows_mutex.synchronize { @running_workflows[run_id] }
219
+ # If instance is not there, we create it out of lock then store it under lock
220
+ unless instance
221
+ instance = yield
222
+ @running_workflows_mutex.synchronize { @running_workflows[run_id] = instance }
223
+ end
224
+ instance
225
+ end
226
+
227
+ def evict_running_workflow(run_id, cache_remove_job)
228
+ @running_workflows_mutex.synchronize { @running_workflows.delete(run_id) }
229
+ @on_eviction&.call(run_id, cache_remove_job)
230
+ end
231
+
232
+ def evict_all
233
+ @running_workflows_mutex.synchronize { @running_workflows.clear }
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Temporalio
4
+ # @!visibility private
5
+ module Internal
6
+ end
7
+ 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
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/internal/proto_utils'
4
+
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
+
14
+ # Options for retrying workflows and activities.
15
+ #
16
+ # @!attribute initial_interval
17
+ # @return [Float] Backoff interval in seconds for the first retry. Default 1.0.
18
+ # @!attribute backoff_coefficient
19
+ # @return [Float] Coefficient to multiply previous backoff interval by to get new interval. Default 2.0.
20
+ # @!attribute max_interval
21
+ # @return [Float, nil] Maximum backoff interval in seconds between retries. Default 100x `initial_interval`.
22
+ # @!attribute max_attempts
23
+ # @return [Integer] Maximum number of attempts. If `0`, the default, there is no maximum.
24
+ # @!attribute non_retryable_error_types
25
+ # @return [Array<String>, nil] List of error types that are not retryable.
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
+ )
54
+ super
55
+ end
56
+
57
+ # @!visibility private
58
+ def _to_proto
59
+ raise 'Initial interval cannot be negative' if initial_interval.negative?
60
+ raise 'Backoff coefficient cannot be less than 1' if backoff_coefficient < 1
61
+ raise 'Max interval cannot be negative' if max_interval&.negative?
62
+ raise 'Max interval cannot be less than initial interval' if max_interval && max_interval < initial_interval
63
+ raise 'Max attempts cannot be negative' if max_attempts.negative?
64
+
65
+ Api::Common::V1::RetryPolicy.new(
66
+ initial_interval: Internal::ProtoUtils.seconds_to_duration(initial_interval),
67
+ backoff_coefficient:,
68
+ maximum_interval: Internal::ProtoUtils.seconds_to_duration(max_interval),
69
+ maximum_attempts: max_attempts,
70
+ non_retryable_error_types:
71
+ )
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Temporalio
4
+ class Runtime
5
+ # Metric buffer for use with a runtime to capture metrics. Only one metric buffer can be associated with a runtime
6
+ # and {retrieve_updates} cannot be called before the runtime is created. Once runtime created, users should
7
+ # regularly call {retrieve_updates} to drain the buffer.
8
+ #
9
+ # @note WARNING: It is important that the buffer size is set to a high number and that {retrieve_updates} is called
10
+ # regularly to drain the buffer. If the buffer is full, metric updates will be dropped and an error will be
11
+ # logged.
12
+ class MetricBuffer
13
+ # Enumerates for the duration format.
14
+ module DurationFormat
15
+ # Durations are millisecond integers.
16
+ MILLISECONDS = :milliseconds
17
+
18
+ # Durations are second floats.
19
+ SECONDS = :seconds
20
+ end
21
+
22
+ Update = Data.define(:metric, :value, :attributes)
23
+
24
+ # Metric buffer update.
25
+ #
26
+ # @note WARNING: The constructor of this class should not be invoked by users and may change in incompatible ways
27
+ # in the future.
28
+ #
29
+ # @!attribute metric
30
+ # @return [Metric] Metric for this update. For performance reasons, this is created lazily on first use and is
31
+ # the same object each time an update on this metric exists.
32
+ # @!attribute value
33
+ # @return [Integer, Float] Metric value for this update.
34
+ # @!attribute attributes
35
+ # @return [Hash{String => String, Integer, Float, Boolean}] Attributes for this value as a frozen hash.
36
+ # For performance reasons this is sometimes the same hash if the attribute set is reused at a metric level.
37
+ class Update # rubocop:disable Lint/EmptyClass
38
+ # DEV NOTE: This class is instantiated inside Rust, be careful changing it.
39
+ end
40
+
41
+ Metric = Data.define(:name, :description, :unit, :kind)
42
+
43
+ # Metric definition present on an update.
44
+ #
45
+ # @!attribute name
46
+ # @return [String] Name of the metric.
47
+ # @!attribute description
48
+ # @return [String, nil] Description of the metric if any.
49
+ # @!attribute unit
50
+ # @return [String, nil] Unit of the metric if any.
51
+ # @!attribute kind
52
+ # @return [:counter, :histogram, :gauge] Kind of the metric.
53
+ class Metric # rubocop:disable Lint/EmptyClass
54
+ # DEV NOTE: This class is instantiated inside Rust, be careful changing it.
55
+ end
56
+
57
+ # Create a metric buffer with the given size.
58
+ #
59
+ # @note WARNING: It is important that the buffer size is set to a high number and is drained regularly. See
60
+ # {MetricBuffer} warning.
61
+ #
62
+ # @param buffer_size [Integer] Maximum size of the buffer before metrics will be dropped.
63
+ # @param duration_format [DurationFormat] How durations are represented.
64
+ def initialize(buffer_size, duration_format: DurationFormat::MILLISECONDS)
65
+ @buffer_size = buffer_size
66
+ @duration_format = duration_format
67
+ @runtime = nil
68
+ end
69
+
70
+ # Drain the buffer and return all metric updates.
71
+ #
72
+ # @note WARNING: It is important that this is called regularly. See {MetricBuffer} warning.
73
+ #
74
+ # @return [Array<Update>] Updates since last time this was called.
75
+ def retrieve_updates
76
+ raise 'Attempting to retrieve updates before runtime created' unless @runtime
77
+
78
+ @runtime._core_runtime.retrieve_buffered_metrics(@duration_format == DurationFormat::SECONDS)
79
+ end
80
+
81
+ # @!visibility private
82
+ def _buffer_size
83
+ @buffer_size
84
+ end
85
+
86
+ # @!visibility private
87
+ def _set_runtime(runtime)
88
+ raise 'Metric buffer already attached to a runtime' if @runtime
89
+
90
+ @runtime = runtime
91
+ end
92
+ end
93
+ end
94
+ end