temporalio 0.3.0-x86_64-linux-musl → 0.5.0-x86_64-linux-musl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/Gemfile +4 -0
  4. data/Rakefile +1 -1
  5. data/lib/temporalio/activity/cancellation_details.rb +58 -0
  6. data/lib/temporalio/activity/context.rb +17 -1
  7. data/lib/temporalio/activity/definition.rb +45 -4
  8. data/lib/temporalio/activity/info.rb +28 -4
  9. data/lib/temporalio/activity.rb +2 -0
  10. data/lib/temporalio/api/activity/v1/message.rb +1 -1
  11. data/lib/temporalio/api/batch/v1/message.rb +9 -2
  12. data/lib/temporalio/api/cloud/account/v1/message.rb +1 -1
  13. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +11 -2
  14. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +2 -2
  15. data/lib/temporalio/api/cloud/identity/v1/message.rb +7 -2
  16. data/lib/temporalio/api/cloud/namespace/v1/message.rb +6 -2
  17. data/lib/temporalio/api/cloud/nexus/v1/message.rb +3 -2
  18. data/lib/temporalio/api/cloud/operation/v1/message.rb +1 -1
  19. data/lib/temporalio/api/cloud/region/v1/message.rb +1 -1
  20. data/lib/temporalio/api/cloud/resource/v1/message.rb +1 -1
  21. data/lib/temporalio/api/cloud/sink/v1/message.rb +1 -1
  22. data/lib/temporalio/api/cloud/usage/v1/message.rb +1 -1
  23. data/lib/temporalio/api/command/v1/message.rb +2 -2
  24. data/lib/temporalio/api/common/v1/grpc_status.rb +1 -1
  25. data/lib/temporalio/api/common/v1/message.rb +4 -2
  26. data/lib/temporalio/api/deployment/v1/message.rb +39 -0
  27. data/lib/temporalio/api/enums/v1/batch_operation.rb +2 -2
  28. data/lib/temporalio/api/enums/v1/command_type.rb +1 -1
  29. data/lib/temporalio/api/enums/v1/common.rb +5 -2
  30. data/lib/temporalio/api/enums/v1/deployment.rb +24 -0
  31. data/lib/temporalio/api/enums/v1/event_type.rb +2 -2
  32. data/lib/temporalio/api/enums/v1/failed_cause.rb +2 -2
  33. data/lib/temporalio/api/enums/v1/namespace.rb +1 -1
  34. data/lib/temporalio/api/enums/v1/nexus.rb +21 -0
  35. data/lib/temporalio/api/enums/v1/query.rb +1 -1
  36. data/lib/temporalio/api/enums/v1/reset.rb +2 -2
  37. data/lib/temporalio/api/enums/v1/schedule.rb +1 -1
  38. data/lib/temporalio/api/enums/v1/task_queue.rb +1 -1
  39. data/lib/temporalio/api/enums/v1/update.rb +1 -1
  40. data/lib/temporalio/api/enums/v1/workflow.rb +3 -2
  41. data/lib/temporalio/api/errordetails/v1/message.rb +4 -2
  42. data/lib/temporalio/api/export/v1/message.rb +1 -1
  43. data/lib/temporalio/api/failure/v1/message.rb +5 -2
  44. data/lib/temporalio/api/filter/v1/message.rb +1 -1
  45. data/lib/temporalio/api/history/v1/message.rb +6 -2
  46. data/lib/temporalio/api/namespace/v1/message.rb +1 -1
  47. data/lib/temporalio/api/nexus/v1/message.rb +3 -2
  48. data/lib/temporalio/api/operatorservice/v1/request_response.rb +1 -1
  49. data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
  50. data/lib/temporalio/api/payload_visitor.rb +162 -7
  51. data/lib/temporalio/api/protocol/v1/message.rb +1 -1
  52. data/lib/temporalio/api/query/v1/message.rb +3 -2
  53. data/lib/temporalio/api/replication/v1/message.rb +1 -1
  54. data/lib/temporalio/api/rules/v1/message.rb +27 -0
  55. data/lib/temporalio/api/schedule/v1/message.rb +2 -2
  56. data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +1 -1
  57. data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +1 -1
  58. data/lib/temporalio/api/sdk/v1/user_metadata.rb +1 -1
  59. data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +1 -1
  60. data/lib/temporalio/api/taskqueue/v1/message.rb +5 -2
  61. data/lib/temporalio/api/testservice/v1/request_response.rb +1 -1
  62. data/lib/temporalio/api/testservice/v1/service.rb +1 -1
  63. data/lib/temporalio/api/update/v1/message.rb +1 -1
  64. data/lib/temporalio/api/version/v1/message.rb +1 -1
  65. data/lib/temporalio/api/worker/v1/message.rb +30 -0
  66. data/lib/temporalio/api/workflow/v1/message.rb +22 -2
  67. data/lib/temporalio/api/workflowservice/v1/request_response.rb +58 -12
  68. data/lib/temporalio/api/workflowservice/v1/service.rb +2 -2
  69. data/lib/temporalio/api.rb +1 -0
  70. data/lib/temporalio/client/async_activity_handle.rb +12 -4
  71. data/lib/temporalio/client/connection/cloud_service.rb +60 -0
  72. data/lib/temporalio/client/connection/workflow_service.rb +343 -28
  73. data/lib/temporalio/client/interceptor.rb +64 -7
  74. data/lib/temporalio/client/schedule.rb +35 -3
  75. data/lib/temporalio/client/with_start_workflow_operation.rb +123 -0
  76. data/lib/temporalio/client/workflow_execution.rb +19 -0
  77. data/lib/temporalio/client/workflow_handle.rb +47 -7
  78. data/lib/temporalio/client/workflow_update_handle.rb +9 -3
  79. data/lib/temporalio/client.rb +231 -4
  80. data/lib/temporalio/common_enums.rb +14 -0
  81. data/lib/temporalio/contrib/open_telemetry.rb +474 -0
  82. data/lib/temporalio/converters/data_converter.rb +18 -8
  83. data/lib/temporalio/converters/failure_converter.rb +6 -3
  84. data/lib/temporalio/converters/payload_converter/binary_null.rb +2 -2
  85. data/lib/temporalio/converters/payload_converter/binary_plain.rb +2 -2
  86. data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +2 -2
  87. data/lib/temporalio/converters/payload_converter/composite.rb +6 -4
  88. data/lib/temporalio/converters/payload_converter/encoding.rb +4 -2
  89. data/lib/temporalio/converters/payload_converter/json_plain.rb +2 -2
  90. data/lib/temporalio/converters/payload_converter/json_protobuf.rb +2 -2
  91. data/lib/temporalio/converters/payload_converter.rb +16 -6
  92. data/lib/temporalio/error/failure.rb +19 -1
  93. data/lib/temporalio/error.rb +2 -1
  94. data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.so +0 -0
  95. data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
  96. data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
  97. data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +1 -1
  98. data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +3 -2
  99. data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +1 -1
  100. data/lib/temporalio/internal/bridge/api/common/common.rb +3 -2
  101. data/lib/temporalio/internal/bridge/api/core_interface.rb +1 -1
  102. data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +1 -1
  103. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +3 -2
  104. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +2 -2
  105. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +3 -2
  106. data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +3 -2
  107. data/lib/temporalio/internal/bridge/runtime.rb +3 -0
  108. data/lib/temporalio/internal/bridge/testing.rb +3 -0
  109. data/lib/temporalio/internal/bridge/worker.rb +28 -4
  110. data/lib/temporalio/internal/bridge.rb +1 -1
  111. data/lib/temporalio/internal/client/implementation.rb +281 -51
  112. data/lib/temporalio/internal/proto_utils.rb +38 -6
  113. data/lib/temporalio/internal/worker/activity_worker.rb +107 -25
  114. data/lib/temporalio/internal/worker/multi_runner.rb +2 -2
  115. data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +8 -6
  116. data/lib/temporalio/internal/worker/workflow_instance/context.rb +96 -5
  117. data/lib/temporalio/internal/worker/workflow_instance/details.rb +7 -2
  118. data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +2 -2
  119. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +64 -18
  120. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +39 -40
  121. data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +22 -2
  122. data/lib/temporalio/internal/worker/workflow_instance.rb +134 -55
  123. data/lib/temporalio/internal/worker/workflow_worker.rb +19 -6
  124. data/lib/temporalio/priority.rb +59 -0
  125. data/lib/temporalio/runtime/metric_buffer.rb +94 -0
  126. data/lib/temporalio/runtime.rb +48 -10
  127. data/lib/temporalio/search_attributes.rb +13 -0
  128. data/lib/temporalio/testing/activity_environment.rb +49 -10
  129. data/lib/temporalio/testing/workflow_environment.rb +29 -6
  130. data/lib/temporalio/version.rb +1 -1
  131. data/lib/temporalio/versioning_override.rb +56 -0
  132. data/lib/temporalio/worker/deployment_options.rb +45 -0
  133. data/lib/temporalio/worker/illegal_workflow_call_validator.rb +64 -0
  134. data/lib/temporalio/worker/interceptor.rb +16 -1
  135. data/lib/temporalio/worker/poller_behavior.rb +61 -0
  136. data/lib/temporalio/worker/thread_pool.rb +6 -6
  137. data/lib/temporalio/worker/workflow_executor/thread_pool.rb +9 -3
  138. data/lib/temporalio/worker/workflow_replayer.rb +19 -13
  139. data/lib/temporalio/worker.rb +97 -27
  140. data/lib/temporalio/worker_deployment_version.rb +67 -0
  141. data/lib/temporalio/workflow/child_workflow_handle.rb +10 -2
  142. data/lib/temporalio/workflow/definition.rb +217 -35
  143. data/lib/temporalio/workflow/external_workflow_handle.rb +3 -1
  144. data/lib/temporalio/workflow/future.rb +2 -2
  145. data/lib/temporalio/workflow/info.rb +26 -1
  146. data/lib/temporalio/workflow.rb +113 -15
  147. data/lib/temporalio.rb +1 -0
  148. data/temporalio.gemspec +3 -1
  149. metadata +33 -4
@@ -9,6 +9,7 @@ require 'temporalio/client/connection'
9
9
  require 'temporalio/client/interceptor'
10
10
  require 'temporalio/client/schedule'
11
11
  require 'temporalio/client/schedule_handle'
12
+ require 'temporalio/client/with_start_workflow_operation'
12
13
  require 'temporalio/client/workflow_execution'
13
14
  require 'temporalio/client/workflow_execution_count'
14
15
  require 'temporalio/client/workflow_handle'
@@ -41,21 +42,18 @@ module Temporalio
41
42
  end
42
43
 
43
44
  def initialize(client)
44
- super(nil)
45
+ super(nil) # steep:ignore
45
46
  @client = client
46
47
  end
47
48
 
48
49
  def start_workflow(input)
49
- # TODO(cretz): Signal/update with start
50
50
  req = Api::WorkflowService::V1::StartWorkflowExecutionRequest.new(
51
51
  request_id: SecureRandom.uuid,
52
52
  namespace: @client.namespace,
53
- workflow_type: Api::Common::V1::WorkflowType.new(
54
- name: Workflow::Definition._workflow_type_from_workflow_parameter(input.workflow)
55
- ),
53
+ workflow_type: Api::Common::V1::WorkflowType.new(name: input.workflow),
56
54
  workflow_id: input.workflow_id,
57
55
  task_queue: Api::TaskQueue::V1::TaskQueue.new(name: input.task_queue.to_s),
58
- input: @client.data_converter.to_payloads(input.args),
56
+ input: @client.data_converter.to_payloads(input.args, hints: input.arg_hints),
59
57
  workflow_execution_timeout: ProtoUtils.seconds_to_duration(input.execution_timeout),
60
58
  workflow_run_timeout: ProtoUtils.seconds_to_duration(input.run_timeout),
61
59
  workflow_task_timeout: ProtoUtils.seconds_to_duration(input.task_timeout),
@@ -68,7 +66,12 @@ module Temporalio
68
66
  search_attributes: input.search_attributes&._to_proto,
69
67
  workflow_start_delay: ProtoUtils.seconds_to_duration(input.start_delay),
70
68
  request_eager_execution: input.request_eager_start,
71
- header: ProtoUtils.headers_to_proto(input.headers, @client.data_converter)
69
+ user_metadata: ProtoUtils.to_user_metadata(
70
+ input.static_summary, input.static_details, @client.data_converter
71
+ ),
72
+ header: ProtoUtils.headers_to_proto(input.headers, @client.data_converter),
73
+ priority: input.priority._to_proto,
74
+ versioning_override: input.versioning_override&._to_proto
72
75
  )
73
76
 
74
77
  # Send request
@@ -100,29 +103,251 @@ module Temporalio
100
103
  id: input.workflow_id,
101
104
  run_id: nil,
102
105
  result_run_id: resp.run_id,
103
- first_execution_run_id: resp.run_id
106
+ first_execution_run_id: resp.run_id,
107
+ result_hint: input.result_hint
104
108
  )
105
109
  end
106
110
 
107
- def list_workflows(input)
108
- Enumerator.new do |yielder|
109
- req = Api::WorkflowService::V1::ListWorkflowExecutionsRequest.new(
110
- namespace: @client.namespace,
111
- query: input.query || ''
112
- )
111
+ def start_update_with_start_workflow(input)
112
+ raise ArgumentError, 'Start operation is required' unless input.start_workflow_operation
113
+
114
+ if input.start_workflow_operation.options.id_conflict_policy == WorkflowIDConflictPolicy::UNSPECIFIED
115
+ raise ArgumentError, 'ID conflict policy is required in start operation'
116
+ end
117
+
118
+ # Try to mark used before using
119
+ input.start_workflow_operation._mark_used
120
+
121
+ # Build request
122
+ start_options = input.start_workflow_operation.options
123
+ start_req = _start_workflow_request_from_with_start_options(
124
+ Api::WorkflowService::V1::StartWorkflowExecutionRequest, start_options
125
+ )
126
+ req = Api::WorkflowService::V1::ExecuteMultiOperationRequest.new(
127
+ namespace: @client.namespace,
128
+ operations: [
129
+ Api::WorkflowService::V1::ExecuteMultiOperationRequest::Operation.new(start_workflow: start_req),
130
+ Api::WorkflowService::V1::ExecuteMultiOperationRequest::Operation.new(
131
+ update_workflow: Api::WorkflowService::V1::UpdateWorkflowExecutionRequest.new(
132
+ namespace: @client.namespace,
133
+ workflow_execution: Api::Common::V1::WorkflowExecution.new(
134
+ workflow_id: start_options.id
135
+ ),
136
+ request: Api::Update::V1::Request.new(
137
+ meta: Api::Update::V1::Meta.new(
138
+ update_id: input.update_id,
139
+ identity: @client.connection.identity
140
+ ),
141
+ input: Api::Update::V1::Input.new(
142
+ name: input.update,
143
+ args: @client.data_converter.to_payloads(input.args, hints: input.arg_hints),
144
+ header: Internal::ProtoUtils.headers_to_proto(input.headers, @client.data_converter)
145
+ )
146
+ ),
147
+ wait_policy: Api::Update::V1::WaitPolicy.new(
148
+ lifecycle_stage: input.wait_for_stage
149
+ )
150
+ )
151
+ )
152
+ ]
153
+ )
154
+
155
+ # Continually try to start until an exception occurs, the user-asked stage is reached, or the stage is
156
+ # accepted. But we will set the workflow handle as soon as we can.
157
+ # @type var update_resp: untyped
158
+ update_resp = nil
159
+ run_id = nil
160
+ begin
113
161
  loop do
114
- resp = @client.workflow_service.list_workflow_executions(
115
- req,
116
- rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
162
+ resp = @client.workflow_service.execute_multi_operation(
163
+ req, rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
117
164
  )
118
- resp.executions.each do |raw_info|
119
- yielder << Temporalio::Client::WorkflowExecution.new(raw_info, @client.data_converter)
165
+ run_id = resp.responses.first.start_workflow.run_id
166
+ # Set workflow handle (no-op if already set)
167
+ input.start_workflow_operation._set_workflow_handle(
168
+ Temporalio::Client::WorkflowHandle.new(
169
+ client: @client,
170
+ id: start_options.id,
171
+ run_id: nil,
172
+ result_run_id: run_id,
173
+ first_execution_run_id: run_id,
174
+ result_hint: start_options.result_hint
175
+ )
176
+ )
177
+ update_resp = resp.responses.last.update_workflow
178
+
179
+ # We're only done if the response stage is at least accepted
180
+ if update_resp && Api::Enums::V1::UpdateWorkflowExecutionLifecycleStage.resolve(update_resp.stage) >=
181
+ Temporalio::Client::WorkflowUpdateWaitStage::ACCEPTED
182
+ break
120
183
  end
121
- break if resp.next_page_token.empty?
184
+ end
122
185
 
123
- req.next_page_token = resp.next_page_token
186
+ # If the user wants to wait until completed, we must poll until outcome if not already there
187
+ if input.wait_for_stage == Temporalio::Client::WorkflowUpdateWaitStage::COMPLETED && update_resp.outcome
188
+ update_resp.outcome = @client._impl.poll_workflow_update(
189
+ Temporalio::Client::Interceptor::PollWorkflowUpdateInput.new(
190
+ workflow_id: start_options.id,
191
+ run_id:,
192
+ update_id: input.update_id,
193
+ rpc_options: input.rpc_options
194
+ )
195
+ )
196
+ end
197
+ rescue Error => e
198
+ # If this is a multi-operation failure, set exception to the first present, non-OK, non-aborted error
199
+ if e.is_a?(Error::RPCError)
200
+ multi_err = e.grpc_status.details&.first&.unpack(Api::ErrorDetails::V1::MultiOperationExecutionFailure)
201
+ if multi_err
202
+ non_aborted = multi_err.statuses.find do |s|
203
+ # Exists, not-ok, not-aborted
204
+ s && s.code != Error::RPCError::Code::OK &&
205
+ !s.details&.first&.is(Api::Failure::V1::MultiOperationExecutionAborted)
206
+ end
207
+ if non_aborted
208
+ e = Error::RPCError.new(
209
+ non_aborted.message,
210
+ code: non_aborted.code,
211
+ raw_grpc_status: Api::Common::V1::GrpcStatus.new(
212
+ code: non_aborted.code, message: non_aborted.message, details: non_aborted.details.to_a
213
+ )
214
+ )
215
+ end
216
+ end
217
+ end
218
+ if e.is_a?(Error::RPCError)
219
+ # Deadline exceeded or cancel is a special error type
220
+ if e.code == Error::RPCError::Code::DEADLINE_EXCEEDED || e.code == Error::RPCError::Code::CANCELED
221
+ e = Error::WorkflowUpdateRPCTimeoutOrCanceledError.new
222
+ elsif e.code == Error::RPCError::Code::ALREADY_EXISTS && e.grpc_status.details.first
223
+ # Unpack and set already started if that's the error
224
+ details = e.grpc_status.details.first.unpack(
225
+ Api::ErrorDetails::V1::WorkflowExecutionAlreadyStartedFailure
226
+ )
227
+ if details
228
+ e = Error::WorkflowAlreadyStartedError.new(
229
+ workflow_id: start_options.id,
230
+ workflow_type: start_req.workflow_type,
231
+ run_id: details.run_id
232
+ )
233
+ end
234
+ end
235
+ end
236
+ # Cancel is a special type
237
+ e = Error::WorkflowUpdateRPCTimeoutOrCanceledError.new if e.is_a?(Error::CanceledError)
238
+ # Before we raise here, we want to try to set the start operation exception (no-op if already set with a
239
+ # handle)
240
+ input.start_workflow_operation._set_workflow_handle(e)
241
+ raise e
242
+ end
243
+
244
+ # Return handle
245
+ Temporalio::Client::WorkflowUpdateHandle.new(
246
+ client: @client,
247
+ id: input.update_id,
248
+ workflow_id: start_options.id,
249
+ workflow_run_id: run_id,
250
+ known_outcome: update_resp.outcome,
251
+ result_hint: input.result_hint
252
+ )
253
+ end
254
+
255
+ def signal_with_start_workflow(input)
256
+ raise ArgumentError, 'Start operation is required' unless input.start_workflow_operation
257
+
258
+ # Try to mark used before using
259
+ input.start_workflow_operation._mark_used
260
+
261
+ # Build req
262
+ start_options = input.start_workflow_operation.options
263
+ req = _start_workflow_request_from_with_start_options(
264
+ Api::WorkflowService::V1::SignalWithStartWorkflowExecutionRequest, start_options
265
+ )
266
+ req.signal_name = input.signal
267
+ req.signal_input = @client.data_converter.to_payloads(input.args, hints: input.arg_hints)
268
+
269
+ # Send request
270
+ begin
271
+ resp = @client.workflow_service.signal_with_start_workflow_execution(
272
+ req,
273
+ rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
274
+ )
275
+ rescue Error::RPCError => e
276
+ # Unpack and raise already started if that's the error, otherwise default raise
277
+ if e.code == Error::RPCError::Code::ALREADY_EXISTS && e.grpc_status.details.first
278
+ details = e.grpc_status.details.first.unpack(
279
+ Api::ErrorDetails::V1::WorkflowExecutionAlreadyStartedFailure
280
+ )
281
+ if details
282
+ e = Error::WorkflowAlreadyStartedError.new(
283
+ workflow_id: req.workflow_id,
284
+ workflow_type: req.workflow_type.name,
285
+ run_id: details.run_id
286
+ )
287
+ end
124
288
  end
289
+ # Before we raise here, we want to the start operation exception
290
+ input.start_workflow_operation._set_workflow_handle(e)
291
+ raise e
125
292
  end
293
+
294
+ # Set handle and return handle
295
+ handle = Temporalio::Client::WorkflowHandle.new(
296
+ client: @client,
297
+ id: start_options.id,
298
+ run_id: nil,
299
+ result_run_id: resp.run_id,
300
+ first_execution_run_id: resp.run_id,
301
+ result_hint: start_options.result_hint
302
+ )
303
+ input.start_workflow_operation._set_workflow_handle(handle)
304
+ handle
305
+ end
306
+
307
+ def _start_workflow_request_from_with_start_options(klass, start_options)
308
+ klass.new(
309
+ request_id: SecureRandom.uuid,
310
+ namespace: @client.namespace,
311
+ workflow_type: Api::Common::V1::WorkflowType.new(name: start_options.workflow),
312
+ workflow_id: start_options.id,
313
+ task_queue: Api::TaskQueue::V1::TaskQueue.new(name: start_options.task_queue.to_s),
314
+ input: @client.data_converter.to_payloads(start_options.args, hints: start_options.arg_hints),
315
+ workflow_execution_timeout: ProtoUtils.seconds_to_duration(start_options.execution_timeout),
316
+ workflow_run_timeout: ProtoUtils.seconds_to_duration(start_options.run_timeout),
317
+ workflow_task_timeout: ProtoUtils.seconds_to_duration(start_options.task_timeout),
318
+ identity: @client.connection.identity,
319
+ workflow_id_reuse_policy: start_options.id_reuse_policy,
320
+ workflow_id_conflict_policy: start_options.id_conflict_policy,
321
+ retry_policy: start_options.retry_policy&._to_proto,
322
+ cron_schedule: start_options.cron_schedule,
323
+ memo: ProtoUtils.memo_to_proto(start_options.memo, @client.data_converter),
324
+ search_attributes: start_options.search_attributes&._to_proto,
325
+ workflow_start_delay: ProtoUtils.seconds_to_duration(start_options.start_delay),
326
+ user_metadata: ProtoUtils.to_user_metadata(
327
+ start_options.static_summary, start_options.static_details, @client.data_converter
328
+ ),
329
+ header: ProtoUtils.headers_to_proto(start_options.headers, @client.data_converter)
330
+ )
331
+ end
332
+
333
+ def list_workflow_page(input)
334
+ req = Api::WorkflowService::V1::ListWorkflowExecutionsRequest.new(
335
+ namespace: @client.namespace,
336
+ query: input.query || '',
337
+ next_page_token: input.next_page_token,
338
+ page_size: input.page_size
339
+ )
340
+ resp = @client.workflow_service.list_workflow_executions(
341
+ req,
342
+ rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
343
+ )
344
+ executions = resp.executions.map do |raw_info|
345
+ Temporalio::Client::WorkflowExecution.new(raw_info, @client.data_converter)
346
+ end
347
+ Temporalio::Client::ListWorkflowPage.new(
348
+ executions: executions,
349
+ next_page_token: resp.next_page_token
350
+ )
126
351
  end
127
352
 
128
353
  def count_workflows(input)
@@ -191,8 +416,8 @@ module Temporalio
191
416
  workflow_id: input.workflow_id,
192
417
  run_id: input.run_id || ''
193
418
  ),
194
- signal_name: Workflow::Definition::Signal._name_from_parameter(input.signal),
195
- input: @client.data_converter.to_payloads(input.args),
419
+ signal_name: input.signal,
420
+ input: @client.data_converter.to_payloads(input.args, hints: input.arg_hints),
196
421
  header: Internal::ProtoUtils.headers_to_proto(input.headers, @client.data_converter),
197
422
  identity: @client.connection.identity,
198
423
  request_id: SecureRandom.uuid
@@ -212,8 +437,8 @@ module Temporalio
212
437
  run_id: input.run_id || ''
213
438
  ),
214
439
  query: Api::Query::V1::WorkflowQuery.new(
215
- query_type: Workflow::Definition::Query._name_from_parameter(input.query),
216
- query_args: @client.data_converter.to_payloads(input.args),
440
+ query_type: input.query,
441
+ query_args: @client.data_converter.to_payloads(input.args, hints: input.arg_hints),
217
442
  header: Internal::ProtoUtils.headers_to_proto(input.headers, @client.data_converter)
218
443
  ),
219
444
  query_reject_condition: input.reject_condition || 0
@@ -233,7 +458,7 @@ module Temporalio
233
458
  ))
234
459
  end
235
460
 
236
- results = @client.data_converter.from_payloads(resp.query_result)
461
+ results = @client.data_converter.from_payloads(resp.query_result, hints: Array(input.result_hint))
237
462
  warn("Expected 0 or 1 query result, got #{results.size}") if results.size > 1
238
463
  results&.first
239
464
  end
@@ -255,8 +480,8 @@ module Temporalio
255
480
  identity: @client.connection.identity
256
481
  ),
257
482
  input: Api::Update::V1::Input.new(
258
- name: Workflow::Definition::Update._name_from_parameter(input.update),
259
- args: @client.data_converter.to_payloads(input.args),
483
+ name: input.update,
484
+ args: @client.data_converter.to_payloads(input.args, hints: input.arg_hints),
260
485
  header: Internal::ProtoUtils.headers_to_proto(input.headers, @client.data_converter)
261
486
  )
262
487
  ),
@@ -270,6 +495,10 @@ module Temporalio
270
495
  # the user cannot specify sooner than ACCEPTED)
271
496
  # @type var resp: untyped
272
497
  resp = nil
498
+ expected_stage = ProtoUtils.enum_to_int(Api::Enums::V1::UpdateWorkflowExecutionLifecycleStage,
499
+ req.wait_policy.lifecycle_stage)
500
+ accepted_stage = ProtoUtils.enum_to_int(Api::Enums::V1::UpdateWorkflowExecutionLifecycleStage,
501
+ Temporalio::Client::WorkflowUpdateWaitStage::ACCEPTED)
273
502
  loop do
274
503
  resp = @client.workflow_service.update_workflow_execution(
275
504
  req,
@@ -278,17 +507,17 @@ module Temporalio
278
507
 
279
508
  # We're only done if the response stage is after the requested stage
280
509
  # or the response stage is accepted
281
- if resp.stage >= req.wait_policy.lifecycle_stage ||
282
- resp.stage >= Temporalio::Client::WorkflowUpdateWaitStage::ACCEPTED
283
- break
284
- end
510
+ actual_stage = ProtoUtils.enum_to_int(Api::Enums::V1::UpdateWorkflowExecutionLifecycleStage, resp.stage)
511
+ break if actual_stage >= expected_stage || actual_stage >= accepted_stage
285
512
  rescue Error::RPCError => e
286
513
  # Deadline exceeded or cancel is a special error type
287
- if e.code == Error::RPCError::Code::DEADLINE_EXCEEDED || e.code == Error::RPCError::Code::CANCELLED
514
+ if e.code == Error::RPCError::Code::DEADLINE_EXCEEDED || e.code == Error::RPCError::Code::CANCELED
288
515
  raise Error::WorkflowUpdateRPCTimeoutOrCanceledError
289
516
  end
290
517
 
291
518
  raise
519
+ rescue Error::CanceledError
520
+ raise Error::WorkflowUpdateRPCTimeoutOrCanceledError
292
521
  end
293
522
 
294
523
  # If the user wants to wait until completed, we must poll until outcome
@@ -309,7 +538,8 @@ module Temporalio
309
538
  id: input.update_id,
310
539
  workflow_id: input.workflow_id,
311
540
  workflow_run_id: input.run_id,
312
- known_outcome: resp.outcome
541
+ known_outcome: resp.outcome,
542
+ result_hint: input.result_hint
313
543
  )
314
544
  end
315
545
 
@@ -338,7 +568,7 @@ module Temporalio
338
568
  return resp.outcome if resp.outcome
339
569
  rescue Error::RPCError => e
340
570
  # Deadline exceeded or cancel is a special error type
341
- if e.code == Error::RPCError::Code::DEADLINE_EXCEEDED || e.code == Error::RPCError::Code::CANCELLED
571
+ if e.code == Error::RPCError::Code::DEADLINE_EXCEEDED || e.code == Error::RPCError::Code::CANCELED
342
572
  raise Error::WorkflowUpdateRPCTimeoutOrCanceledError
343
573
  end
344
574
 
@@ -584,7 +814,7 @@ module Temporalio
584
814
  activity_id: input.task_token_or_id_reference.activity_id,
585
815
  namespace: @client.namespace,
586
816
  identity: @client.connection.identity,
587
- details: @client.data_converter.to_payloads(input.details)
817
+ details: @client.data_converter.to_payloads(input.details, hints: input.detail_hints)
588
818
  ),
589
819
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
590
820
  )
@@ -594,7 +824,7 @@ module Temporalio
594
824
  task_token: input.task_token_or_id_reference,
595
825
  namespace: @client.namespace,
596
826
  identity: @client.connection.identity,
597
- details: @client.data_converter.to_payloads(input.details)
827
+ details: @client.data_converter.to_payloads(input.details, hints: input.detail_hints)
598
828
  ),
599
829
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
600
830
  )
@@ -613,7 +843,7 @@ module Temporalio
613
843
  activity_id: input.task_token_or_id_reference.activity_id,
614
844
  namespace: @client.namespace,
615
845
  identity: @client.connection.identity,
616
- result: @client.data_converter.to_payloads([input.result])
846
+ result: @client.data_converter.to_payloads([input.result], hints: Array(input.result_hint))
617
847
  ),
618
848
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
619
849
  )
@@ -623,7 +853,7 @@ module Temporalio
623
853
  task_token: input.task_token_or_id_reference,
624
854
  namespace: @client.namespace,
625
855
  identity: @client.connection.identity,
626
- result: @client.data_converter.to_payloads([input.result])
856
+ result: @client.data_converter.to_payloads([input.result], hints: Array(input.result_hint))
627
857
  ),
628
858
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
629
859
  )
@@ -632,6 +862,14 @@ module Temporalio
632
862
  end
633
863
 
634
864
  def fail_async_activity(input)
865
+ last_heartbeat_details = if input.last_heartbeat_details.empty?
866
+ nil
867
+ else
868
+ @client.data_converter.to_payloads(
869
+ input.last_heartbeat_details,
870
+ hints: input.last_heartbeat_detail_hints
871
+ )
872
+ end
635
873
  if input.task_token_or_id_reference.is_a?(Temporalio::Client::ActivityIDReference)
636
874
  @client.workflow_service.respond_activity_task_failed_by_id(
637
875
  Api::WorkflowService::V1::RespondActivityTaskFailedByIdRequest.new(
@@ -641,11 +879,7 @@ module Temporalio
641
879
  namespace: @client.namespace,
642
880
  identity: @client.connection.identity,
643
881
  failure: @client.data_converter.to_failure(input.error),
644
- last_heartbeat_details: if input.last_heartbeat_details.empty?
645
- nil
646
- else
647
- @client.data_converter.to_payloads(input.last_heartbeat_details)
648
- end
882
+ last_heartbeat_details:
649
883
  ),
650
884
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
651
885
  )
@@ -656,11 +890,7 @@ module Temporalio
656
890
  namespace: @client.namespace,
657
891
  identity: @client.connection.identity,
658
892
  failure: @client.data_converter.to_failure(input.error),
659
- last_heartbeat_details: if input.last_heartbeat_details.empty?
660
- nil
661
- else
662
- @client.data_converter.to_payloads(input.last_heartbeat_details)
663
- end
893
+ last_heartbeat_details:
664
894
  ),
665
895
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
666
896
  )
@@ -677,7 +907,7 @@ module Temporalio
677
907
  activity_id: input.task_token_or_id_reference.activity_id,
678
908
  namespace: @client.namespace,
679
909
  identity: @client.connection.identity,
680
- details: @client.data_converter.to_payloads(input.details)
910
+ details: @client.data_converter.to_payloads(input.details, hints: input.detail_hints)
681
911
  ),
682
912
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
683
913
  )
@@ -687,7 +917,7 @@ module Temporalio
687
917
  task_token: input.task_token_or_id_reference,
688
918
  namespace: @client.namespace,
689
919
  identity: @client.connection.identity,
690
- details: @client.data_converter.to_payloads(input.details)
920
+ details: @client.data_converter.to_payloads(input.details, hints: input.detail_hints)
691
921
  ),
692
922
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
693
923
  )
@@ -51,7 +51,7 @@ module Temporalio
51
51
  end
52
52
 
53
53
  def self.memo_from_proto(memo, converter)
54
- return nil if memo.nil? || memo.fields.size.zero? # rubocop:disable Style/ZeroLengthPredicate Google Maps don't have empty
54
+ return nil if memo.nil? || memo.fields.size.zero? # rubocop:disable Style/ZeroLengthPredicate -- Google Maps don't have empty
55
55
 
56
56
  memo.fields.each_with_object({}) { |(key, val), h| h[key] = converter.from_payload(val) } # rubocop:disable Style/HashTransformValues
57
57
  end
@@ -73,7 +73,7 @@ module Temporalio
73
73
  end
74
74
 
75
75
  def self.headers_from_proto_map(headers, converter)
76
- return nil if headers.nil? || headers.size.zero? # rubocop:disable Style/ZeroLengthPredicate Google Maps don't have empty
76
+ return nil if headers.nil? || headers.size.zero? # rubocop:disable Style/ZeroLengthPredicate -- Google Maps don't have empty
77
77
 
78
78
  headers.each_with_object({}) do |(key, val), h| # rubocop:disable Style/HashTransformValues
79
79
  # @type var h: Hash[String, Object?]
@@ -94,16 +94,48 @@ module Temporalio
94
94
  enum_val
95
95
  end
96
96
 
97
- def self.convert_from_payload_array(converter, payloads)
97
+ def self.convert_from_payload_array(converter, payloads, hints:)
98
98
  return [] if payloads.empty?
99
99
 
100
- converter.from_payloads(Api::Common::V1::Payloads.new(payloads:))
100
+ converter.from_payloads(Api::Common::V1::Payloads.new(payloads:), hints:)
101
101
  end
102
102
 
103
- def self.convert_to_payload_array(converter, values)
103
+ def self.convert_to_payload_array(converter, values, hints:)
104
104
  return [] if values.empty?
105
105
 
106
- converter.to_payloads(values).payloads.to_ary
106
+ converter.to_payloads(values, hints:).payloads.to_ary
107
+ end
108
+
109
+ def self.assert_non_reserved_name(name)
110
+ name = name&.to_s # In case it's a symbol or not present
111
+ return unless name
112
+ raise "'#{name}' cannot start with '__temporal_'" if name.start_with?('__temporal_')
113
+ # Might as well disable __stack_trace and __enhanced_stack_trace everywhere even though technically it's only
114
+ # reserved for queries
115
+ raise "'#{name}' name invalid" if name == '__stack_trace' || name == '__enhanced_stack_trace'
116
+ end
117
+
118
+ def self.reserved_name?(name)
119
+ name = name&.to_s # In case it's a symbol or not present
120
+ return false unless name
121
+
122
+ name.start_with?('__temporal_') || name == '__stack_trace' || name == '__enhanced_stack_trace'
123
+ end
124
+
125
+ def self.to_user_metadata(summary, details, converter)
126
+ return nil if (!summary || summary.empty?) && (!details || details.empty?)
127
+
128
+ metadata = Temporalio::Api::Sdk::V1::UserMetadata.new
129
+ metadata.summary = converter.to_payload(summary) if summary && !summary.empty?
130
+ metadata.details = converter.to_payload(details) if details && !details.empty?
131
+ metadata
132
+ end
133
+
134
+ def self.from_user_metadata(metadata, converter)
135
+ [
136
+ (converter.from_payload(metadata.summary) if metadata&.summary), #: String?
137
+ (converter.from_payload(metadata.details) if metadata&.details) #: String?
138
+ ]
107
139
  end
108
140
 
109
141
  class LazyMemo