temporalio 0.2.0-x86_64-linux

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 (128) hide show
  1. checksums.yaml +7 -0
  2. data/lib/temporalio/activity/complete_async_error.rb +11 -0
  3. data/lib/temporalio/activity/context.rb +107 -0
  4. data/lib/temporalio/activity/definition.rb +77 -0
  5. data/lib/temporalio/activity/info.rb +63 -0
  6. data/lib/temporalio/activity.rb +69 -0
  7. data/lib/temporalio/api/batch/v1/message.rb +31 -0
  8. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +93 -0
  9. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +25 -0
  10. data/lib/temporalio/api/cloud/cloudservice.rb +3 -0
  11. data/lib/temporalio/api/cloud/identity/v1/message.rb +36 -0
  12. data/lib/temporalio/api/cloud/namespace/v1/message.rb +35 -0
  13. data/lib/temporalio/api/cloud/operation/v1/message.rb +27 -0
  14. data/lib/temporalio/api/cloud/region/v1/message.rb +23 -0
  15. data/lib/temporalio/api/command/v1/message.rb +46 -0
  16. data/lib/temporalio/api/common/v1/grpc_status.rb +23 -0
  17. data/lib/temporalio/api/common/v1/message.rb +41 -0
  18. data/lib/temporalio/api/enums/v1/batch_operation.rb +22 -0
  19. data/lib/temporalio/api/enums/v1/command_type.rb +21 -0
  20. data/lib/temporalio/api/enums/v1/common.rb +26 -0
  21. data/lib/temporalio/api/enums/v1/event_type.rb +21 -0
  22. data/lib/temporalio/api/enums/v1/failed_cause.rb +26 -0
  23. data/lib/temporalio/api/enums/v1/namespace.rb +23 -0
  24. data/lib/temporalio/api/enums/v1/query.rb +22 -0
  25. data/lib/temporalio/api/enums/v1/reset.rb +23 -0
  26. data/lib/temporalio/api/enums/v1/schedule.rb +21 -0
  27. data/lib/temporalio/api/enums/v1/task_queue.rb +25 -0
  28. data/lib/temporalio/api/enums/v1/update.rb +22 -0
  29. data/lib/temporalio/api/enums/v1/workflow.rb +30 -0
  30. data/lib/temporalio/api/errordetails/v1/message.rb +42 -0
  31. data/lib/temporalio/api/export/v1/message.rb +24 -0
  32. data/lib/temporalio/api/failure/v1/message.rb +35 -0
  33. data/lib/temporalio/api/filter/v1/message.rb +27 -0
  34. data/lib/temporalio/api/history/v1/message.rb +90 -0
  35. data/lib/temporalio/api/namespace/v1/message.rb +31 -0
  36. data/lib/temporalio/api/nexus/v1/message.rb +40 -0
  37. data/lib/temporalio/api/operatorservice/v1/request_response.rb +49 -0
  38. data/lib/temporalio/api/operatorservice/v1/service.rb +23 -0
  39. data/lib/temporalio/api/operatorservice.rb +3 -0
  40. data/lib/temporalio/api/protocol/v1/message.rb +23 -0
  41. data/lib/temporalio/api/query/v1/message.rb +27 -0
  42. data/lib/temporalio/api/replication/v1/message.rb +26 -0
  43. data/lib/temporalio/api/schedule/v1/message.rb +42 -0
  44. data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +25 -0
  45. data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +21 -0
  46. data/lib/temporalio/api/sdk/v1/user_metadata.rb +23 -0
  47. data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +23 -0
  48. data/lib/temporalio/api/taskqueue/v1/message.rb +45 -0
  49. data/lib/temporalio/api/update/v1/message.rb +33 -0
  50. data/lib/temporalio/api/version/v1/message.rb +26 -0
  51. data/lib/temporalio/api/workflow/v1/message.rb +43 -0
  52. data/lib/temporalio/api/workflowservice/v1/request_response.rb +189 -0
  53. data/lib/temporalio/api/workflowservice/v1/service.rb +23 -0
  54. data/lib/temporalio/api/workflowservice.rb +3 -0
  55. data/lib/temporalio/api.rb +13 -0
  56. data/lib/temporalio/cancellation.rb +150 -0
  57. data/lib/temporalio/client/activity_id_reference.rb +32 -0
  58. data/lib/temporalio/client/async_activity_handle.rb +110 -0
  59. data/lib/temporalio/client/connection/cloud_service.rb +648 -0
  60. data/lib/temporalio/client/connection/operator_service.rb +249 -0
  61. data/lib/temporalio/client/connection/service.rb +41 -0
  62. data/lib/temporalio/client/connection/workflow_service.rb +1218 -0
  63. data/lib/temporalio/client/connection.rb +270 -0
  64. data/lib/temporalio/client/interceptor.rb +316 -0
  65. data/lib/temporalio/client/workflow_execution.rb +103 -0
  66. data/lib/temporalio/client/workflow_execution_count.rb +36 -0
  67. data/lib/temporalio/client/workflow_execution_status.rb +18 -0
  68. data/lib/temporalio/client/workflow_handle.rb +446 -0
  69. data/lib/temporalio/client/workflow_query_reject_condition.rb +14 -0
  70. data/lib/temporalio/client/workflow_update_handle.rb +67 -0
  71. data/lib/temporalio/client/workflow_update_wait_stage.rb +17 -0
  72. data/lib/temporalio/client.rb +404 -0
  73. data/lib/temporalio/common_enums.rb +24 -0
  74. data/lib/temporalio/converters/data_converter.rb +102 -0
  75. data/lib/temporalio/converters/failure_converter.rb +200 -0
  76. data/lib/temporalio/converters/payload_codec.rb +26 -0
  77. data/lib/temporalio/converters/payload_converter/binary_null.rb +34 -0
  78. data/lib/temporalio/converters/payload_converter/binary_plain.rb +35 -0
  79. data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +42 -0
  80. data/lib/temporalio/converters/payload_converter/composite.rb +62 -0
  81. data/lib/temporalio/converters/payload_converter/encoding.rb +35 -0
  82. data/lib/temporalio/converters/payload_converter/json_plain.rb +44 -0
  83. data/lib/temporalio/converters/payload_converter/json_protobuf.rb +41 -0
  84. data/lib/temporalio/converters/payload_converter.rb +73 -0
  85. data/lib/temporalio/converters.rb +9 -0
  86. data/lib/temporalio/error/failure.rb +219 -0
  87. data/lib/temporalio/error.rb +147 -0
  88. data/lib/temporalio/internal/bridge/3.1/temporalio_bridge.so +0 -0
  89. data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.so +0 -0
  90. data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
  91. data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +34 -0
  92. data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +31 -0
  93. data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +33 -0
  94. data/lib/temporalio/internal/bridge/api/common/common.rb +26 -0
  95. data/lib/temporalio/internal/bridge/api/core_interface.rb +36 -0
  96. data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +27 -0
  97. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +52 -0
  98. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +54 -0
  99. data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +30 -0
  100. data/lib/temporalio/internal/bridge/api.rb +3 -0
  101. data/lib/temporalio/internal/bridge/client.rb +90 -0
  102. data/lib/temporalio/internal/bridge/runtime.rb +53 -0
  103. data/lib/temporalio/internal/bridge/testing.rb +46 -0
  104. data/lib/temporalio/internal/bridge/worker.rb +83 -0
  105. data/lib/temporalio/internal/bridge.rb +36 -0
  106. data/lib/temporalio/internal/client/implementation.rb +525 -0
  107. data/lib/temporalio/internal/proto_utils.rb +54 -0
  108. data/lib/temporalio/internal/worker/activity_worker.rb +345 -0
  109. data/lib/temporalio/internal/worker/multi_runner.rb +169 -0
  110. data/lib/temporalio/internal.rb +7 -0
  111. data/lib/temporalio/retry_policy.rb +51 -0
  112. data/lib/temporalio/runtime.rb +271 -0
  113. data/lib/temporalio/scoped_logger.rb +96 -0
  114. data/lib/temporalio/search_attributes.rb +300 -0
  115. data/lib/temporalio/testing/activity_environment.rb +132 -0
  116. data/lib/temporalio/testing/workflow_environment.rb +137 -0
  117. data/lib/temporalio/testing.rb +10 -0
  118. data/lib/temporalio/version.rb +5 -0
  119. data/lib/temporalio/worker/activity_executor/fiber.rb +49 -0
  120. data/lib/temporalio/worker/activity_executor/thread_pool.rb +254 -0
  121. data/lib/temporalio/worker/activity_executor.rb +55 -0
  122. data/lib/temporalio/worker/interceptor.rb +88 -0
  123. data/lib/temporalio/worker/tuner.rb +151 -0
  124. data/lib/temporalio/worker.rb +426 -0
  125. data/lib/temporalio/workflow_history.rb +22 -0
  126. data/lib/temporalio.rb +7 -0
  127. data/temporalio.gemspec +28 -0
  128. metadata +189 -0
@@ -0,0 +1,525 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'google/protobuf/well_known_types'
4
+ require 'securerandom'
5
+ require 'temporalio/api'
6
+ require 'temporalio/client/activity_id_reference'
7
+ require 'temporalio/client/async_activity_handle'
8
+ require 'temporalio/client/connection'
9
+ require 'temporalio/client/interceptor'
10
+ require 'temporalio/client/workflow_execution'
11
+ require 'temporalio/client/workflow_execution_count'
12
+ require 'temporalio/client/workflow_handle'
13
+ require 'temporalio/common_enums'
14
+ require 'temporalio/converters'
15
+ require 'temporalio/error'
16
+ require 'temporalio/error/failure'
17
+ require 'temporalio/internal/proto_utils'
18
+ require 'temporalio/runtime'
19
+ require 'temporalio/search_attributes'
20
+
21
+ module Temporalio
22
+ module Internal
23
+ module Client
24
+ class Implementation < Temporalio::Client::Interceptor::Outbound
25
+ def initialize(client)
26
+ super(nil)
27
+ @client = client
28
+ end
29
+
30
+ def start_workflow(input)
31
+ # TODO(cretz): Signal/update with start
32
+ req = Api::WorkflowService::V1::StartWorkflowExecutionRequest.new(
33
+ request_id: SecureRandom.uuid,
34
+ namespace: @client.namespace,
35
+ workflow_type: Api::Common::V1::WorkflowType.new(name: input.workflow.to_s),
36
+ workflow_id: input.workflow_id,
37
+ task_queue: Api::TaskQueue::V1::TaskQueue.new(name: input.task_queue.to_s),
38
+ input: @client.data_converter.to_payloads(input.args),
39
+ workflow_execution_timeout: ProtoUtils.seconds_to_duration(input.execution_timeout),
40
+ workflow_run_timeout: ProtoUtils.seconds_to_duration(input.run_timeout),
41
+ workflow_task_timeout: ProtoUtils.seconds_to_duration(input.task_timeout),
42
+ identity: @client.connection.identity,
43
+ workflow_id_reuse_policy: input.id_reuse_policy,
44
+ workflow_id_conflict_policy: input.id_conflict_policy,
45
+ retry_policy: input.retry_policy&.to_proto,
46
+ cron_schedule: input.cron_schedule,
47
+ memo: ProtoUtils.memo_to_proto(input.memo, @client.data_converter),
48
+ search_attributes: input.search_attributes&.to_proto,
49
+ workflow_start_delay: ProtoUtils.seconds_to_duration(input.start_delay),
50
+ request_eager_execution: input.request_eager_start,
51
+ header: input.headers
52
+ )
53
+
54
+ # Send request
55
+ begin
56
+ resp = @client.workflow_service.start_workflow_execution(
57
+ req,
58
+ rpc_retry: true,
59
+ rpc_metadata: input.rpc_metadata,
60
+ rpc_timeout: input.rpc_timeout
61
+ )
62
+ rescue Error::RPCError => e
63
+ # Unpack and raise already started if that's the error, otherwise default raise
64
+ if e.code == Error::RPCError::Code::ALREADY_EXISTS && e.grpc_status.details.first
65
+ details = e.grpc_status.details.first.unpack(
66
+ Api::ErrorDetails::V1::WorkflowExecutionAlreadyStartedFailure
67
+ )
68
+ if details
69
+ raise Error::WorkflowAlreadyStartedError.new(
70
+ workflow_id: req.workflow_id,
71
+ workflow_type: req.workflow_type.name,
72
+ run_id: details.run_id
73
+ )
74
+ end
75
+ end
76
+ raise
77
+ end
78
+
79
+ # Return handle
80
+ Temporalio::Client::WorkflowHandle.new(
81
+ client: @client,
82
+ id: input.workflow_id,
83
+ run_id: nil,
84
+ result_run_id: resp.run_id,
85
+ first_execution_run_id: resp.run_id
86
+ )
87
+ end
88
+
89
+ def list_workflows(input)
90
+ Enumerator.new do |yielder|
91
+ req = Api::WorkflowService::V1::ListWorkflowExecutionsRequest.new(
92
+ namespace: @client.namespace,
93
+ query: input.query || ''
94
+ )
95
+ loop do
96
+ resp = @client.workflow_service.list_workflow_executions(
97
+ req,
98
+ rpc_retry: true,
99
+ rpc_metadata: input.rpc_metadata,
100
+ rpc_timeout: input.rpc_timeout
101
+ )
102
+ resp.executions.each do |raw_info|
103
+ yielder << Temporalio::Client::WorkflowExecution.new(raw_info, @client.data_converter)
104
+ end
105
+ break if resp.next_page_token.empty?
106
+
107
+ req.next_page_token = resp.next_page_token
108
+ end
109
+ end
110
+ end
111
+
112
+ def count_workflows(input)
113
+ resp = @client.workflow_service.count_workflow_executions(
114
+ Api::WorkflowService::V1::CountWorkflowExecutionsRequest.new(
115
+ namespace: @client.namespace,
116
+ query: input.query || ''
117
+ ),
118
+ rpc_retry: true,
119
+ rpc_metadata: input.rpc_metadata,
120
+ rpc_timeout: input.rpc_timeout
121
+ )
122
+ Temporalio::Client::WorkflowExecutionCount.new(
123
+ resp.count,
124
+ resp.groups.map do |group|
125
+ Temporalio::Client::WorkflowExecutionCount::AggregationGroup.new(
126
+ group.count,
127
+ group.group_values.map { |payload| SearchAttributes.value_from_payload(payload) }
128
+ )
129
+ end
130
+ )
131
+ end
132
+
133
+ def describe_workflow(input)
134
+ resp = @client.workflow_service.describe_workflow_execution(
135
+ Api::WorkflowService::V1::DescribeWorkflowExecutionRequest.new(
136
+ namespace: @client.namespace,
137
+ execution: Api::Common::V1::WorkflowExecution.new(
138
+ workflow_id: input.workflow_id,
139
+ run_id: input.run_id || ''
140
+ )
141
+ ),
142
+ rpc_retry: true,
143
+ rpc_metadata: input.rpc_metadata,
144
+ rpc_timeout: input.rpc_timeout
145
+ )
146
+ Temporalio::Client::WorkflowExecution::Description.new(resp, @client.data_converter)
147
+ end
148
+
149
+ def fetch_workflow_history_events(input)
150
+ Enumerator.new do |yielder|
151
+ req = Api::WorkflowService::V1::GetWorkflowExecutionHistoryRequest.new(
152
+ namespace: @client.namespace,
153
+ execution: Api::Common::V1::WorkflowExecution.new(
154
+ workflow_id: input.workflow_id,
155
+ run_id: input.run_id || ''
156
+ ),
157
+ wait_new_event: input.wait_new_event,
158
+ history_event_filter_type: input.event_filter_type,
159
+ skip_archival: input.skip_archival
160
+ )
161
+ loop do
162
+ resp = @client.workflow_service.get_workflow_execution_history(
163
+ req,
164
+ rpc_retry: true,
165
+ rpc_metadata: input.rpc_metadata,
166
+ rpc_timeout: input.rpc_timeout
167
+ )
168
+ resp.history&.events&.each { |event| yielder << event }
169
+ break if resp.next_page_token.empty?
170
+
171
+ req.next_page_token = resp.next_page_token
172
+ end
173
+ end
174
+ end
175
+
176
+ def signal_workflow(input)
177
+ @client.workflow_service.signal_workflow_execution(
178
+ Api::WorkflowService::V1::SignalWorkflowExecutionRequest.new(
179
+ namespace: @client.namespace,
180
+ workflow_execution: Api::Common::V1::WorkflowExecution.new(
181
+ workflow_id: input.workflow_id,
182
+ run_id: input.run_id || ''
183
+ ),
184
+ signal_name: input.signal,
185
+ input: @client.data_converter.to_payloads(input.args),
186
+ header: input.headers,
187
+ identity: @client.connection.identity,
188
+ request_id: SecureRandom.uuid
189
+ ),
190
+ rpc_retry: true,
191
+ rpc_metadata: input.rpc_metadata,
192
+ rpc_timeout: input.rpc_timeout
193
+ )
194
+ nil
195
+ end
196
+
197
+ def query_workflow(input)
198
+ begin
199
+ resp = @client.workflow_service.query_workflow(
200
+ Api::WorkflowService::V1::QueryWorkflowRequest.new(
201
+ namespace: @client.namespace,
202
+ execution: Api::Common::V1::WorkflowExecution.new(
203
+ workflow_id: input.workflow_id,
204
+ run_id: input.run_id || ''
205
+ ),
206
+ query: Api::Query::V1::WorkflowQuery.new(
207
+ query_type: input.query,
208
+ query_args: @client.data_converter.to_payloads(input.args),
209
+ header: input.headers
210
+ ),
211
+ query_reject_condition: input.reject_condition || 0
212
+ ),
213
+ rpc_retry: true,
214
+ rpc_metadata: input.rpc_metadata,
215
+ rpc_timeout: input.rpc_timeout
216
+ )
217
+ rescue Error::RPCError => e
218
+ # If the status is INVALID_ARGUMENT, we can assume it's a query failed
219
+ # error
220
+ raise Error::WorkflowQueryFailedError, e.message if e.code == Error::RPCError::Code::INVALID_ARGUMENT
221
+
222
+ raise
223
+ end
224
+ unless resp.query_rejected.nil?
225
+ raise Error::WorkflowQueryRejectedError.new(status: ProtoUtils.enum_to_int(
226
+ Api::Enums::V1::WorkflowExecutionStatus, resp.query_rejected.status
227
+ ))
228
+ end
229
+
230
+ results = @client.data_converter.from_payloads(resp.query_result)
231
+ warn("Expected 0 or 1 query result, got #{results.size}") if results.size > 1
232
+ results&.first
233
+ end
234
+
235
+ def start_workflow_update(input)
236
+ if input.wait_for_stage == Temporalio::Client::WorkflowUpdateWaitStage::ADMITTED
237
+ raise ArgumentError, 'ADMITTED wait stage not supported'
238
+ end
239
+
240
+ req = Api::WorkflowService::V1::UpdateWorkflowExecutionRequest.new(
241
+ namespace: @client.namespace,
242
+ workflow_execution: Api::Common::V1::WorkflowExecution.new(
243
+ workflow_id: input.workflow_id,
244
+ run_id: input.run_id || ''
245
+ ),
246
+ request: Api::Update::V1::Request.new(
247
+ meta: Api::Update::V1::Meta.new(
248
+ update_id: input.update_id,
249
+ identity: @client.connection.identity
250
+ ),
251
+ input: Api::Update::V1::Input.new(
252
+ name: input.update,
253
+ args: @client.data_converter.to_payloads(input.args),
254
+ header: input.headers
255
+ )
256
+ ),
257
+ wait_policy: Api::Update::V1::WaitPolicy.new(
258
+ lifecycle_stage: input.wait_for_stage
259
+ )
260
+ )
261
+
262
+ # Repeatedly try to invoke start until the update reaches user-provided
263
+ # wait stage or is at least ACCEPTED (as of the time of this writing,
264
+ # the user cannot specify sooner than ACCEPTED)
265
+ # @type var resp: untyped
266
+ resp = nil
267
+ loop do
268
+ resp = @client.workflow_service.update_workflow_execution(
269
+ req,
270
+ rpc_retry: true,
271
+ rpc_metadata: input.rpc_metadata,
272
+ rpc_timeout: input.rpc_timeout
273
+ )
274
+
275
+ # We're only done if the response stage is after the requested stage
276
+ # or the response stage is accepted
277
+ if resp.stage >= req.wait_policy.lifecycle_stage ||
278
+ resp.stage >= Temporalio::Client::WorkflowUpdateWaitStage::ACCEPTED
279
+ break
280
+ end
281
+ rescue Error::RPCError => e
282
+ # Deadline exceeded or cancel is a special error type
283
+ if e.code == Error::RPCError::Code::DEADLINE_EXCEEDED || e.code == Error::RPCError::Code::CANCELLED
284
+ raise Error::WorkflowUpdateRPCTimeoutOrCanceledError
285
+ end
286
+
287
+ raise
288
+ end
289
+
290
+ # If the user wants to wait until completed, we must poll until outcome
291
+ # if not already there
292
+ if input.wait_for_stage == Temporalio::Client::WorkflowUpdateWaitStage::COMPLETED && !resp.outcome
293
+ resp.outcome = @client._impl.poll_workflow_update(
294
+ Temporalio::Client::Interceptor::PollWorkflowUpdateInput.new(
295
+ workflow_id: input.workflow_id,
296
+ run_id: input.run_id,
297
+ update_id: input.update_id,
298
+ rpc_metadata: input.rpc_metadata,
299
+ rpc_timeout: input.rpc_timeout
300
+ )
301
+ )
302
+ end
303
+
304
+ Temporalio::Client::WorkflowUpdateHandle.new(
305
+ client: @client,
306
+ id: input.update_id,
307
+ workflow_id: input.workflow_id,
308
+ workflow_run_id: input.run_id,
309
+ known_outcome: resp.outcome
310
+ )
311
+ end
312
+
313
+ def poll_workflow_update(input)
314
+ req = Api::WorkflowService::V1::PollWorkflowExecutionUpdateRequest.new(
315
+ namespace: @client.namespace,
316
+ update_ref: Api::Update::V1::UpdateRef.new(
317
+ workflow_execution: Api::Common::V1::WorkflowExecution.new(
318
+ workflow_id: input.workflow_id,
319
+ run_id: input.run_id || ''
320
+ ),
321
+ update_id: input.update_id
322
+ ),
323
+ identity: @client.connection.identity,
324
+ wait_policy: Api::Update::V1::WaitPolicy.new(
325
+ lifecycle_stage: Temporalio::Client::WorkflowUpdateWaitStage::COMPLETED
326
+ )
327
+ )
328
+
329
+ # Continue polling as long as we have no outcome
330
+ loop do
331
+ resp = @client.workflow_service.poll_workflow_execution_update(
332
+ req,
333
+ rpc_retry: true,
334
+ rpc_metadata: input.rpc_metadata,
335
+ rpc_timeout: input.rpc_timeout
336
+ )
337
+ return resp.outcome if resp.outcome
338
+ rescue Error::RPCError => e
339
+ # Deadline exceeded or cancel is a special error type
340
+ if e.code == Error::RPCError::Code::DEADLINE_EXCEEDED || e.code == Error::RPCError::Code::CANCELLED
341
+ raise Error::WorkflowUpdateRPCTimeoutOrCanceledError
342
+ end
343
+
344
+ raise
345
+ end
346
+ end
347
+
348
+ def cancel_workflow(input)
349
+ @client.workflow_service.request_cancel_workflow_execution(
350
+ Api::WorkflowService::V1::RequestCancelWorkflowExecutionRequest.new(
351
+ namespace: @client.namespace,
352
+ workflow_execution: Api::Common::V1::WorkflowExecution.new(
353
+ workflow_id: input.workflow_id,
354
+ run_id: input.run_id || ''
355
+ ),
356
+ first_execution_run_id: input.first_execution_run_id,
357
+ identity: @client.connection.identity,
358
+ request_id: SecureRandom.uuid
359
+ ),
360
+ rpc_retry: true,
361
+ rpc_metadata: input.rpc_metadata,
362
+ rpc_timeout: input.rpc_timeout
363
+ )
364
+ nil
365
+ end
366
+
367
+ def terminate_workflow(input)
368
+ @client.workflow_service.terminate_workflow_execution(
369
+ Api::WorkflowService::V1::TerminateWorkflowExecutionRequest.new(
370
+ namespace: @client.namespace,
371
+ workflow_execution: Api::Common::V1::WorkflowExecution.new(
372
+ workflow_id: input.workflow_id,
373
+ run_id: input.run_id || ''
374
+ ),
375
+ reason: input.reason || '',
376
+ first_execution_run_id: input.first_execution_run_id,
377
+ details: @client.data_converter.to_payloads(input.details),
378
+ identity: @client.connection.identity
379
+ ),
380
+ rpc_retry: true,
381
+ rpc_metadata: input.rpc_metadata,
382
+ rpc_timeout: input.rpc_timeout
383
+ )
384
+ nil
385
+ end
386
+
387
+ def heartbeat_async_activity(input)
388
+ resp = if input.task_token_or_id_reference.is_a?(Temporalio::Client::ActivityIDReference)
389
+ @client.workflow_service.record_activity_task_heartbeat_by_id(
390
+ Api::WorkflowService::V1::RecordActivityTaskHeartbeatByIdRequest.new(
391
+ workflow_id: input.task_token_or_id_reference.workflow_id,
392
+ run_id: input.task_token_or_id_reference.run_id,
393
+ activity_id: input.task_token_or_id_reference.activity_id,
394
+ namespace: @client.namespace,
395
+ identity: @client.connection.identity,
396
+ details: @client.data_converter.to_payloads(input.details)
397
+ ),
398
+ rpc_retry: true,
399
+ rpc_metadata: input.rpc_metadata,
400
+ rpc_timeout: input.rpc_timeout
401
+ )
402
+ else
403
+ @client.workflow_service.record_activity_task_heartbeat(
404
+ Api::WorkflowService::V1::RecordActivityTaskHeartbeatRequest.new(
405
+ task_token: input.task_token_or_id_reference,
406
+ namespace: @client.namespace,
407
+ identity: @client.connection.identity,
408
+ details: @client.data_converter.to_payloads(input.details)
409
+ ),
410
+ rpc_retry: true,
411
+ rpc_metadata: input.rpc_metadata,
412
+ rpc_timeout: input.rpc_timeout
413
+ )
414
+ end
415
+ raise Error::AsyncActivityCanceledError if resp.cancel_requested
416
+
417
+ nil
418
+ end
419
+
420
+ def complete_async_activity(input)
421
+ if input.task_token_or_id_reference.is_a?(Temporalio::Client::ActivityIDReference)
422
+ @client.workflow_service.respond_activity_task_completed_by_id(
423
+ Api::WorkflowService::V1::RespondActivityTaskCompletedByIdRequest.new(
424
+ workflow_id: input.task_token_or_id_reference.workflow_id,
425
+ run_id: input.task_token_or_id_reference.run_id,
426
+ activity_id: input.task_token_or_id_reference.activity_id,
427
+ namespace: @client.namespace,
428
+ identity: @client.connection.identity,
429
+ result: @client.data_converter.to_payloads([input.result])
430
+ ),
431
+ rpc_retry: true,
432
+ rpc_metadata: input.rpc_metadata,
433
+ rpc_timeout: input.rpc_timeout
434
+ )
435
+ else
436
+ @client.workflow_service.respond_activity_task_completed(
437
+ Api::WorkflowService::V1::RespondActivityTaskCompletedRequest.new(
438
+ task_token: input.task_token_or_id_reference,
439
+ namespace: @client.namespace,
440
+ identity: @client.connection.identity,
441
+ result: @client.data_converter.to_payloads([input.result])
442
+ ),
443
+ rpc_retry: true,
444
+ rpc_metadata: input.rpc_metadata,
445
+ rpc_timeout: input.rpc_timeout
446
+ )
447
+ end
448
+ nil
449
+ end
450
+
451
+ def fail_async_activity(input)
452
+ if input.task_token_or_id_reference.is_a?(Temporalio::Client::ActivityIDReference)
453
+ @client.workflow_service.respond_activity_task_failed_by_id(
454
+ Api::WorkflowService::V1::RespondActivityTaskFailedByIdRequest.new(
455
+ workflow_id: input.task_token_or_id_reference.workflow_id,
456
+ run_id: input.task_token_or_id_reference.run_id,
457
+ activity_id: input.task_token_or_id_reference.activity_id,
458
+ namespace: @client.namespace,
459
+ identity: @client.connection.identity,
460
+ failure: @client.data_converter.to_failure(input.error),
461
+ last_heartbeat_details: if input.last_heartbeat_details.empty?
462
+ nil
463
+ else
464
+ @client.data_converter.to_payloads(input.last_heartbeat_details)
465
+ end
466
+ ),
467
+ rpc_retry: true,
468
+ rpc_metadata: input.rpc_metadata,
469
+ rpc_timeout: input.rpc_timeout
470
+ )
471
+ else
472
+ @client.workflow_service.respond_activity_task_failed(
473
+ Api::WorkflowService::V1::RespondActivityTaskFailedRequest.new(
474
+ task_token: input.task_token_or_id_reference,
475
+ namespace: @client.namespace,
476
+ identity: @client.connection.identity,
477
+ failure: @client.data_converter.to_failure(input.error),
478
+ last_heartbeat_details: if input.last_heartbeat_details.empty?
479
+ nil
480
+ else
481
+ @client.data_converter.to_payloads(input.last_heartbeat_details)
482
+ end
483
+ ),
484
+ rpc_retry: true,
485
+ rpc_metadata: input.rpc_metadata,
486
+ rpc_timeout: input.rpc_timeout
487
+ )
488
+ end
489
+ nil
490
+ end
491
+
492
+ def report_cancellation_async_activity(input)
493
+ if input.task_token_or_id_reference.is_a?(Temporalio::Client::ActivityIDReference)
494
+ @client.workflow_service.respond_activity_task_canceled_by_id(
495
+ Api::WorkflowService::V1::RespondActivityTaskCanceledByIdRequest.new(
496
+ workflow_id: input.task_token_or_id_reference.workflow_id,
497
+ run_id: input.task_token_or_id_reference.run_id,
498
+ activity_id: input.task_token_or_id_reference.activity_id,
499
+ namespace: @client.namespace,
500
+ identity: @client.connection.identity,
501
+ details: @client.data_converter.to_payloads(input.details)
502
+ ),
503
+ rpc_retry: true,
504
+ rpc_metadata: input.rpc_metadata,
505
+ rpc_timeout: input.rpc_timeout
506
+ )
507
+ else
508
+ @client.workflow_service.respond_activity_task_canceled(
509
+ Api::WorkflowService::V1::RespondActivityTaskCanceledRequest.new(
510
+ task_token: input.task_token_or_id_reference,
511
+ namespace: @client.namespace,
512
+ identity: @client.connection.identity,
513
+ details: @client.data_converter.to_payloads(input.details)
514
+ ),
515
+ rpc_retry: true,
516
+ rpc_metadata: input.rpc_metadata,
517
+ rpc_timeout: input.rpc_timeout
518
+ )
519
+ end
520
+ nil
521
+ end
522
+ end
523
+ end
524
+ end
525
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/api'
4
+
5
+ module Temporalio
6
+ module Internal
7
+ module ProtoUtils
8
+ def self.seconds_to_duration(seconds_float)
9
+ return nil if seconds_float.nil?
10
+
11
+ seconds = seconds_float.to_i
12
+ nanos = ((seconds_float - seconds) * 1_000_000_000).round
13
+ Google::Protobuf::Duration.new(seconds:, nanos:)
14
+ end
15
+
16
+ def self.memo_to_proto(hash, converter)
17
+ return nil if hash.nil?
18
+
19
+ Api::Common::V1::Memo.new(fields: hash.transform_values { |val| converter.to_payload(val) })
20
+ end
21
+
22
+ def self.memo_from_proto(memo, converter)
23
+ return nil if memo.nil?
24
+
25
+ memo.fields.each_with_object({}) { |(key, val), h| h[key] = converter.from_payload(val) } # rubocop:disable Style/HashTransformValues
26
+ end
27
+
28
+ def self.string_or(str, default = nil)
29
+ str && !str.empty? ? str : default
30
+ end
31
+
32
+ def self.enum_to_int(enum_mod, enum_val, zero_means_nil: false)
33
+ # Per https://protobuf.dev/reference/ruby/ruby-generated/#enum when
34
+ # enums are read back, they are symbols if they are known or number
35
+ # otherwise
36
+ enum_val = enum_mod.resolve(enum_val) || raise('Unexpected missing symbol') if enum_val.is_a?(Symbol)
37
+ enum_val = nil if zero_means_nil && enum_val.zero?
38
+ enum_val
39
+ end
40
+
41
+ def self.convert_from_payload_array(converter, payloads)
42
+ return [] if payloads.empty?
43
+
44
+ converter.from_payloads(Api::Common::V1::Payloads.new(payloads:))
45
+ end
46
+
47
+ def self.convert_to_payload_array(converter, values)
48
+ return [] if values.empty?
49
+
50
+ converter.to_payloads(values).payloads.to_ary
51
+ end
52
+ end
53
+ end
54
+ end