temporalio 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/Cargo.lock +659 -370
  4. data/Cargo.toml +2 -2
  5. data/Gemfile +3 -3
  6. data/README.md +589 -47
  7. data/Rakefile +10 -296
  8. data/ext/Cargo.toml +1 -0
  9. data/lib/temporalio/activity/complete_async_error.rb +1 -1
  10. data/lib/temporalio/activity/context.rb +5 -2
  11. data/lib/temporalio/activity/definition.rb +163 -65
  12. data/lib/temporalio/activity/info.rb +22 -21
  13. data/lib/temporalio/activity.rb +2 -59
  14. data/lib/temporalio/api/activity/v1/message.rb +25 -0
  15. data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
  16. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +34 -1
  17. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
  18. data/lib/temporalio/api/cloud/identity/v1/message.rb +6 -1
  19. data/lib/temporalio/api/cloud/namespace/v1/message.rb +8 -1
  20. data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
  21. data/lib/temporalio/api/cloud/operation/v1/message.rb +2 -1
  22. data/lib/temporalio/api/cloud/region/v1/message.rb +2 -1
  23. data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
  24. data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
  25. data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
  26. data/lib/temporalio/api/common/v1/message.rb +7 -1
  27. data/lib/temporalio/api/enums/v1/event_type.rb +1 -1
  28. data/lib/temporalio/api/enums/v1/failed_cause.rb +1 -1
  29. data/lib/temporalio/api/enums/v1/reset.rb +1 -1
  30. data/lib/temporalio/api/history/v1/message.rb +1 -1
  31. data/lib/temporalio/api/nexus/v1/message.rb +2 -2
  32. data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
  33. data/lib/temporalio/api/payload_visitor.rb +1513 -0
  34. data/lib/temporalio/api/schedule/v1/message.rb +2 -1
  35. data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
  36. data/lib/temporalio/api/testservice/v1/service.rb +23 -0
  37. data/lib/temporalio/api/workflow/v1/message.rb +1 -1
  38. data/lib/temporalio/api/workflowservice/v1/request_response.rb +17 -2
  39. data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
  40. data/lib/temporalio/api.rb +1 -0
  41. data/lib/temporalio/cancellation.rb +34 -14
  42. data/lib/temporalio/client/async_activity_handle.rb +12 -37
  43. data/lib/temporalio/client/connection/cloud_service.rb +309 -231
  44. data/lib/temporalio/client/connection/operator_service.rb +36 -84
  45. data/lib/temporalio/client/connection/service.rb +6 -5
  46. data/lib/temporalio/client/connection/test_service.rb +111 -0
  47. data/lib/temporalio/client/connection/workflow_service.rb +264 -441
  48. data/lib/temporalio/client/connection.rb +90 -44
  49. data/lib/temporalio/client/interceptor.rb +160 -60
  50. data/lib/temporalio/client/schedule.rb +967 -0
  51. data/lib/temporalio/client/schedule_handle.rb +126 -0
  52. data/lib/temporalio/client/workflow_execution.rb +7 -10
  53. data/lib/temporalio/client/workflow_handle.rb +38 -95
  54. data/lib/temporalio/client/workflow_update_handle.rb +3 -5
  55. data/lib/temporalio/client.rb +122 -42
  56. data/lib/temporalio/common_enums.rb +17 -0
  57. data/lib/temporalio/converters/data_converter.rb +4 -7
  58. data/lib/temporalio/converters/failure_converter.rb +5 -3
  59. data/lib/temporalio/converters/payload_converter/composite.rb +4 -0
  60. data/lib/temporalio/converters/payload_converter.rb +6 -8
  61. data/lib/temporalio/converters/raw_value.rb +20 -0
  62. data/lib/temporalio/error/failure.rb +1 -1
  63. data/lib/temporalio/error.rb +10 -2
  64. data/lib/temporalio/internal/bridge/api/core_interface.rb +5 -1
  65. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
  66. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +5 -1
  67. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +4 -1
  68. data/lib/temporalio/internal/bridge/client.rb +11 -6
  69. data/lib/temporalio/internal/bridge/testing.rb +20 -0
  70. data/lib/temporalio/internal/bridge/worker.rb +2 -0
  71. data/lib/temporalio/internal/bridge.rb +1 -1
  72. data/lib/temporalio/internal/client/implementation.rb +245 -70
  73. data/lib/temporalio/internal/metric.rb +122 -0
  74. data/lib/temporalio/internal/proto_utils.rb +86 -7
  75. data/lib/temporalio/internal/worker/activity_worker.rb +52 -24
  76. data/lib/temporalio/internal/worker/multi_runner.rb +51 -7
  77. data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
  78. data/lib/temporalio/internal/worker/workflow_instance/context.rb +329 -0
  79. data/lib/temporalio/internal/worker/workflow_instance/details.rb +44 -0
  80. data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
  81. data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
  82. data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
  83. data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
  84. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
  85. data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
  86. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +415 -0
  87. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
  88. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
  89. data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +163 -0
  90. data/lib/temporalio/internal/worker/workflow_instance.rb +730 -0
  91. data/lib/temporalio/internal/worker/workflow_worker.rb +196 -0
  92. data/lib/temporalio/metric.rb +109 -0
  93. data/lib/temporalio/retry_policy.rb +37 -14
  94. data/lib/temporalio/runtime.rb +118 -75
  95. data/lib/temporalio/search_attributes.rb +80 -37
  96. data/lib/temporalio/testing/activity_environment.rb +2 -2
  97. data/lib/temporalio/testing/workflow_environment.rb +251 -5
  98. data/lib/temporalio/version.rb +1 -1
  99. data/lib/temporalio/worker/activity_executor/thread_pool.rb +9 -217
  100. data/lib/temporalio/worker/activity_executor.rb +3 -3
  101. data/lib/temporalio/worker/interceptor.rb +340 -66
  102. data/lib/temporalio/worker/thread_pool.rb +237 -0
  103. data/lib/temporalio/worker/workflow_executor/thread_pool.rb +230 -0
  104. data/lib/temporalio/worker/workflow_executor.rb +26 -0
  105. data/lib/temporalio/worker.rb +201 -30
  106. data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
  107. data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
  108. data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
  109. data/lib/temporalio/workflow/definition.rb +566 -0
  110. data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
  111. data/lib/temporalio/workflow/future.rb +151 -0
  112. data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
  113. data/lib/temporalio/workflow/info.rb +82 -0
  114. data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
  115. data/lib/temporalio/workflow/update_info.rb +20 -0
  116. data/lib/temporalio/workflow.rb +523 -0
  117. data/lib/temporalio.rb +4 -0
  118. data/temporalio.gemspec +2 -2
  119. metadata +50 -8
@@ -0,0 +1,967 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/api'
4
+ require 'temporalio/converters'
5
+ require 'temporalio/internal/proto_utils'
6
+ require 'temporalio/retry_policy'
7
+ require 'temporalio/search_attributes'
8
+
9
+ module Temporalio
10
+ class Client
11
+ Schedule = Data.define(
12
+ :action,
13
+ :spec,
14
+ :policy,
15
+ :state
16
+ )
17
+
18
+ # A schedule for periodically running an action.
19
+ #
20
+ # @!attribute action
21
+ # @return [Action] Action taken when scheduled.
22
+ # @!attribute spec
23
+ # @return [Spec] When the action is taken.
24
+ # @!attribute policy
25
+ # @return [Policy] Schedule policies.
26
+ # @!attribute state
27
+ # @return [State] State of the schedule.
28
+ class Schedule
29
+ # @!visibility private
30
+ def self._from_proto(raw_schedule, data_converter)
31
+ Schedule.new(
32
+ action: Action._from_proto(raw_schedule.action, data_converter),
33
+ spec: Spec._from_proto(raw_schedule.spec),
34
+ policy: Policy._from_proto(raw_schedule.policies),
35
+ state: State._from_proto(raw_schedule.state)
36
+ )
37
+ end
38
+
39
+ # Create schedule
40
+ #
41
+ # @param action [Action] Action taken when scheduled.
42
+ # @param spec [Spec] When the action is taken.
43
+ # @param policy [Policy] Schedule policies.
44
+ # @param state [State] State of the schedule.
45
+ def initialize(action:, spec:, policy: Policy.new, state: State.new)
46
+ super
47
+ end
48
+
49
+ # @!visibility private
50
+ def _to_proto(data_converter)
51
+ Api::Schedule::V1::Schedule.new(
52
+ spec: spec._to_proto,
53
+ action: action._to_proto(data_converter),
54
+ policies: policy._to_proto,
55
+ state: state._to_proto
56
+ )
57
+ end
58
+
59
+ Description = Data.define( # rubocop:disable Layout/ClassStructure
60
+ :id,
61
+ :schedule,
62
+ :info,
63
+ :raw_description
64
+ )
65
+
66
+ # Description of a schedule.
67
+ #
68
+ # @!attribute id
69
+ # @return [String] ID of the schedule.
70
+ # @!attribute schedule
71
+ # @return [Schedule] Schedule details.
72
+ # @!attribute info
73
+ # @return [Schedule::Info] Information about the schedule.
74
+ # @!attribute raw_description
75
+ # @return [Api::WorkflowService::V1::DescribeScheduleResponse] Raw description of the schedule.
76
+ class Description
77
+ # @!visibility private
78
+ def initialize(id:, raw_description:, data_converter:)
79
+ @memo = Internal::ProtoUtils::LazyMemo.new(raw_description.memo, data_converter)
80
+ @search_attributes = Internal::ProtoUtils::LazySearchAttributes.new(raw_description.search_attributes)
81
+ # steep:ignore:start
82
+ super(
83
+ id:,
84
+ schedule: Schedule._from_proto(raw_description.schedule, data_converter),
85
+ info: Info.new(raw_info: raw_description.info),
86
+ raw_description:
87
+ )
88
+ # steep:ignore:end
89
+ end
90
+
91
+ # @return [Hash<String, Object>, nil] Memo for the schedule, converted lazily on first call.
92
+ def memo
93
+ @memo.get
94
+ end
95
+
96
+ # @return [SearchAttributes, nil] Search attributes for the schedule, converted lazily on first call.
97
+ def search_attributes
98
+ @search_attributes.get
99
+ end
100
+ end
101
+
102
+ Info = Data.define(
103
+ :num_actions,
104
+ :num_actions_missed_catchup_window,
105
+ :num_actions_skipped_overlap,
106
+ :running_actions,
107
+ :recent_actions,
108
+ :next_action_times,
109
+ :created_at,
110
+ :last_updated_at
111
+ )
112
+
113
+ # Information about a schedule.
114
+ #
115
+ # @!attribute num_actions
116
+ # @return [Integer] Number of actions taken by this schedule.
117
+ # @!attribute num_actions_missed_catchup_window
118
+ # @return [Integer] Number of times an action was skipped due to missing the catchup window.
119
+ # @!attribute num_actions_skipped_overlap
120
+ # @return [Integer] Number of actions skipped due to overlap.
121
+ # @!attribute running_actions
122
+ # @return [Array<ActionExecution>] Currently running actions.
123
+ # @!attribute recent_actions
124
+ # @return [Array<ActionResult>] 10 most recent actions, oldest first.
125
+ # @!attribute next_action_times
126
+ # @return [Array<Time>] Next 10 scheduled action times.
127
+ # @!attribute created_at
128
+ # @return [Time] When the schedule was created.
129
+ # @!attribute last_updated_at
130
+ # @return [Time, nil] When the schedule was last updated.
131
+ class Info
132
+ # @!visibility private
133
+ def initialize(raw_info:)
134
+ # steep:ignore:start
135
+ super(
136
+ num_actions: raw_info.action_count,
137
+ num_actions_missed_catchup_window: raw_info.missed_catchup_window,
138
+ num_actions_skipped_overlap: raw_info.overlap_skipped,
139
+ running_actions: raw_info.running_workflows.map do |w|
140
+ ActionExecution::StartWorkflow.new(raw_execution: w)
141
+ end,
142
+ recent_actions: raw_info.recent_actions.map { |a| ActionResult.new(raw_result: a) },
143
+ next_action_times: raw_info.future_action_times.map { |t| Internal::ProtoUtils.timestamp_to_time(t) },
144
+ created_at: Internal::ProtoUtils.timestamp_to_time(raw_info.create_time),
145
+ last_updated_at: Internal::ProtoUtils.timestamp_to_time(raw_info.update_time)
146
+ )
147
+ # steep:ignore:end
148
+ end
149
+ end
150
+
151
+ # Base module mixed in by specific actions a schedule can take.
152
+ module Action
153
+ # @!visibility private
154
+ def self._from_proto(raw_action, data_converter)
155
+ raise "Unsupported action: #{raw_action.action}" unless raw_action.start_workflow
156
+
157
+ StartWorkflow._from_proto(raw_action.start_workflow, data_converter)
158
+ end
159
+
160
+ # @!visibility private
161
+ def _to_proto(data_converter)
162
+ raise NotImplementedError
163
+ end
164
+
165
+ StartWorkflow = Data.define(
166
+ :workflow,
167
+ :args,
168
+ :id,
169
+ :task_queue,
170
+ :execution_timeout,
171
+ :run_timeout,
172
+ :task_timeout,
173
+ :retry_policy,
174
+ :memo,
175
+ :search_attributes,
176
+ :headers
177
+ )
178
+
179
+ # Schedule action to start a workflow.
180
+ #
181
+ # @!attribute workflow
182
+ # @return [String] Workflow.
183
+ # @!attribute args
184
+ # @return [Array<Object>] Arguments to the workflow.
185
+ # @!attribute id
186
+ # @return [String] Unique identifier for the workflow execution.
187
+ # @!attribute task_queue
188
+ # @return [String] Task queue to run the workflow on.
189
+ # @!attribute execution_timeout
190
+ # @return [Float, nil] Total workflow execution timeout in seconds including retries and continue as new.
191
+ # @!attribute run_timeout
192
+ # @return [Float, nil] Timeout of a single workflow run in seconds.
193
+ # @!attribute task_timeout
194
+ # @return [Float, nil] Timeout of a single workflow task in seconds.
195
+ # @!attribute retry_policy
196
+ # @return [RetryPolicy, nil] Retry policy for the workflow.
197
+ # @!attribute memo
198
+ # @return [Hash<String, Object>, nil] Memo for the workflow.
199
+ # @!attribute search_attributes
200
+ # @return [SearchAttributes, nil] Search attributes for the workflow.
201
+ # @!attribute headers
202
+ # @return [Hash<String, Object>, nil] Headers for the workflow.
203
+ class StartWorkflow
204
+ include Action
205
+
206
+ class << self
207
+ alias _original_new new
208
+
209
+ # Create start-workflow schedule action.
210
+ #
211
+ # @param workflow [Class<Workflow::Definition>, Symbol, String] Workflow.
212
+ # @param args [Array<Object>] Arguments to the workflow.
213
+ # @param id [String] Unique identifier for the workflow execution.
214
+ # @param task_queue [String] Task queue to run the workflow on.
215
+ # @param execution_timeout [Float, nil] Total workflow execution timeout in seconds including retries and
216
+ # continue as new.
217
+ # @param run_timeout [Float, nil] Timeout of a single workflow run in seconds.
218
+ # @param task_timeout [Float, nil] Timeout of a single workflow task in seconds.
219
+ # @param retry_policy [RetryPolicy, nil] Retry policy for the workflow.
220
+ # @param memo [Hash<String, Object>, nil] Memo for the workflow.
221
+ # @param search_attributes [SearchAttributes, nil] Search attributes for the workflow.
222
+ # @param headers [Hash<String, Object>, nil] Headers for the workflow.
223
+ def new(
224
+ workflow,
225
+ *args,
226
+ id:,
227
+ task_queue:,
228
+ execution_timeout: nil,
229
+ run_timeout: nil,
230
+ task_timeout: nil,
231
+ retry_policy: nil,
232
+ memo: nil,
233
+ search_attributes: nil,
234
+ headers: nil
235
+ )
236
+ _original_new( # steep:ignore
237
+ workflow: Workflow::Definition._workflow_type_from_workflow_parameter(workflow),
238
+ args:,
239
+ id:,
240
+ task_queue:,
241
+ execution_timeout:,
242
+ run_timeout:,
243
+ task_timeout:,
244
+ retry_policy:,
245
+ memo:,
246
+ search_attributes:,
247
+ headers:
248
+ )
249
+ end
250
+ end
251
+
252
+ # @!visibility private
253
+ def self._from_proto(raw_info, data_converter)
254
+ StartWorkflow.new(
255
+ raw_info.workflow_type.name,
256
+ *data_converter.from_payloads(raw_info.input),
257
+ id: raw_info.workflow_id,
258
+ task_queue: raw_info.task_queue.name,
259
+ execution_timeout: Internal::ProtoUtils.duration_to_seconds(raw_info.workflow_execution_timeout),
260
+ run_timeout: Internal::ProtoUtils.duration_to_seconds(raw_info.workflow_run_timeout),
261
+ task_timeout: Internal::ProtoUtils.duration_to_seconds(raw_info.workflow_task_timeout),
262
+ retry_policy: raw_info.retry_policy ? RetryPolicy._from_proto(raw_info.retry_policy) : nil,
263
+ memo: Internal::ProtoUtils.memo_from_proto(raw_info.memo, data_converter),
264
+ search_attributes: SearchAttributes._from_proto(raw_info.search_attributes),
265
+ headers: Internal::ProtoUtils.headers_from_proto(raw_info.header, data_converter)
266
+ )
267
+ end
268
+
269
+ # @!visibility private
270
+ def _to_proto(data_converter)
271
+ Api::Schedule::V1::ScheduleAction.new(
272
+ start_workflow: Api::Workflow::V1::NewWorkflowExecutionInfo.new(
273
+ workflow_id: id,
274
+ workflow_type: Api::Common::V1::WorkflowType.new(name: workflow),
275
+ task_queue: Api::TaskQueue::V1::TaskQueue.new(name: task_queue),
276
+ input: data_converter.to_payloads(args),
277
+ workflow_execution_timeout: Internal::ProtoUtils.seconds_to_duration(execution_timeout),
278
+ workflow_run_timeout: Internal::ProtoUtils.seconds_to_duration(run_timeout),
279
+ workflow_task_timeout: Internal::ProtoUtils.seconds_to_duration(task_timeout),
280
+ retry_policy: retry_policy&._to_proto,
281
+ memo: Internal::ProtoUtils.memo_to_proto(memo, data_converter),
282
+ search_attributes: search_attributes&._to_proto,
283
+ header: Internal::ProtoUtils.headers_to_proto(headers, data_converter)
284
+ )
285
+ )
286
+ end
287
+ end
288
+ end
289
+
290
+ # Enumerate that controls what happens when a workflow would be started by a schedule but one is already running.
291
+ module OverlapPolicy
292
+ # Don't start anything. When the workflow completes, the next scheduled event after that time will be
293
+ # considered.
294
+ SKIP = Api::Enums::V1::ScheduleOverlapPolicy::SCHEDULE_OVERLAP_POLICY_SKIP
295
+
296
+ # Start the workflow again soon as the current one completes, but only buffer one start in this way. If another
297
+ # start is supposed to happen when the workflow is running, and one is already buffered, then only the first one
298
+ # will be started after the running workflow finishes.
299
+ BUFFER_ONE = Api::Enums::V1::ScheduleOverlapPolicy::SCHEDULE_OVERLAP_POLICY_BUFFER_ONE
300
+
301
+ # Buffer up any number of starts to all happen sequentially, immediately after the running workflow completes.
302
+ BUFFER_ALL = Api::Enums::V1::ScheduleOverlapPolicy::SCHEDULE_OVERLAP_POLICY_BUFFER_ALL
303
+
304
+ # If there is another workflow running, cancel it, and start the new one after the old one completes
305
+ # cancellation.
306
+ CANCEL_OTHER = Api::Enums::V1::ScheduleOverlapPolicy::SCHEDULE_OVERLAP_POLICY_CANCEL_OTHER
307
+
308
+ # If there is another workflow running, terminate it and start the new one immediately.
309
+ TERMINATE_OTHER = Api::Enums::V1::ScheduleOverlapPolicy::SCHEDULE_OVERLAP_POLICY_TERMINATE_OTHER
310
+
311
+ # Start any number of concurrent workflows. Note that with this policy, last completion result and last failure
312
+ # will not be available since workflows are not sequential.
313
+ ALLOW_ALL = Api::Enums::V1::ScheduleOverlapPolicy::SCHEDULE_OVERLAP_POLICY_ALLOW_ALL
314
+ end
315
+
316
+ Backfill = Data.define(
317
+ :start_at,
318
+ :end_at,
319
+ :overlap
320
+ )
321
+
322
+ # Time period and policy for actions taken as if the time passed right now.
323
+ #
324
+ # @!attribute start_at
325
+ # @return [Time] Start of the range to evaluate the schedule in. This is exclusive.
326
+ # @!attribute end_at
327
+ # @return [Time] End of the range to evaluate the schedule in. This is inclusive.
328
+ # @!attribute overlap
329
+ # @return [OverlapPolicy] Overlap policy.
330
+ class Backfill
331
+ # Create backfill.
332
+ #
333
+ # @param start_at [Time] Start of the range to evaluate the schedule in. This is exclusive.
334
+ # @param end_at [Time] End of the range to evaluate the schedule in. This is inclusive.
335
+ # @param overlap [OverlapPolicy] Overlap policy.
336
+ def initialize(
337
+ start_at:,
338
+ end_at:,
339
+ overlap: nil
340
+ )
341
+ super
342
+ end
343
+
344
+ # @!visibility private
345
+ def _to_proto
346
+ Api::Schedule::V1::BackfillRequest.new(
347
+ start_time: Internal::ProtoUtils.time_to_timestamp(start_at),
348
+ end_time: Internal::ProtoUtils.time_to_timestamp(end_at),
349
+ overlap_policy: overlap || Api::Enums::V1::ScheduleOverlapPolicy::SCHEDULE_OVERLAP_POLICY_UNSPECIFIED
350
+ )
351
+ end
352
+ end
353
+
354
+ # Base module mixed in by specific action executions.
355
+ module ActionExecution
356
+ StartWorkflow = Data.define(
357
+ :workflow_id,
358
+ :first_execution_run_id
359
+ )
360
+
361
+ # Execution of a scheduled workflow start.
362
+ #
363
+ # @!attribute workflow_id
364
+ # @return [String] Workflow ID.
365
+ # @!attribute first_execution_run_id
366
+ # @return [String] Workflow run ID.
367
+ class StartWorkflow
368
+ include ActionExecution
369
+
370
+ # @!visibility private
371
+ def initialize(raw_execution:)
372
+ # steep:ignore:start
373
+ super(
374
+ workflow_id: raw_execution.workflow_id,
375
+ first_execution_run_id: raw_execution.run_id
376
+ )
377
+ # steep:ignore:end
378
+ end
379
+ end
380
+ end
381
+
382
+ ActionResult = Data.define(
383
+ :scheduled_at,
384
+ :started_at,
385
+ :action
386
+ )
387
+
388
+ # Information about when an action took place.
389
+ #
390
+ # @!attribute scheduled_at
391
+ # @return [Time] Scheduled time of the action including jitter.
392
+ # @!attribute started_at
393
+ # @return [Time] When the action actually started.
394
+ # @!attribute action
395
+ # @return [ActionExecution] Action that took place.
396
+ class ActionResult
397
+ # @!visibility private
398
+ def initialize(raw_result:)
399
+ # steep:ignore:start
400
+ super(
401
+ scheduled_at: Internal::ProtoUtils.timestamp_to_time(raw_result.schedule_time),
402
+ started_at: Internal::ProtoUtils.timestamp_to_time(raw_result.actual_time),
403
+ action: ActionExecution::StartWorkflow.new(raw_execution: raw_result.start_workflow_result)
404
+ )
405
+ # steep:ignore:end
406
+ end
407
+ end
408
+
409
+ Spec = Data.define(
410
+ :calendars,
411
+ :intervals,
412
+ :cron_expressions,
413
+ :skip,
414
+ :start_at,
415
+ :end_at,
416
+ :jitter,
417
+ :time_zone_name
418
+ )
419
+
420
+ # Specification of the times scheduled actions may occur.
421
+ #
422
+ # The times are the union of {calendars}, {intervals}, and {cron_expressions} excluding anything in {skip}.
423
+ #
424
+ # @!attribute calendars
425
+ # @return [Array<Calendar>] Calendar-based specification of times.
426
+ # @!attribute intervals
427
+ # @return [Array<Interval>] Interval-based specification of times.
428
+ # @!attribute cron_expressions
429
+ # @return [Array<String>] Cron-based specification of times. This is provided for easy migration
430
+ # from legacy string-based cron scheduling. New uses should use `calendars` instead. These expressions will be
431
+ # translated to calendar-based specifications on the server.
432
+ # @!attribute skip
433
+ # @return [Array<Calendar>] Set of matching calendar times that will be skipped.
434
+ # @!attribute start_at
435
+ # @return [Time, nil] Time before which any matching times will be skipped.
436
+ # @!attribute end_at
437
+ # @return [Time, nil] Time after which any matching times will be skipped.
438
+ # @!attribute jitter
439
+ # @return [Float, nil] Jitter to apply each action. An action's scheduled time will be incremented by a random
440
+ # value between 0 and this value if present (but not past the next schedule).
441
+ # @!attribute time_zone_name
442
+ # @return [String, nil] IANA time zone name, for example `US/Central`.
443
+ class Spec
444
+ # @!visibility private
445
+ def self._from_proto(raw_spec)
446
+ Schedule::Spec.new(
447
+ calendars: raw_spec.structured_calendar.map { |c| Calendar._from_proto(c) },
448
+ intervals: raw_spec.interval.map { |c| Interval._from_proto(c) },
449
+ cron_expressions: raw_spec.cron_string.to_a,
450
+ skip: raw_spec.exclude_structured_calendar.map { |c| Calendar._from_proto(c) },
451
+ start_at: Internal::ProtoUtils.timestamp_to_time(raw_spec.start_time),
452
+ end_at: Internal::ProtoUtils.timestamp_to_time(raw_spec.end_time),
453
+ jitter: Internal::ProtoUtils.duration_to_seconds(raw_spec.jitter),
454
+ time_zone_name: Internal::ProtoUtils.string_or(raw_spec.timezone_name)
455
+ )
456
+ end
457
+
458
+ # Create a spec.
459
+ #
460
+ # @param calendars [Array<Calendar>] Calendar-based specification of times.
461
+ # @param intervals [Array<Interval>] Interval-based specification of times.
462
+ # @param cron_expressions [Array<String>] Cron-based specification of times. This is provided for easy migration
463
+ # from legacy string-based cron scheduling. New uses should use `calendars` instead. These expressions will be
464
+ # translated to calendar-based specifications on the server.
465
+ # @param skip [Array<Calendar>] Set of matching calendar times that will be skipped.
466
+ # @param start_at [Time, nil] Time before which any matching times will be skipped.
467
+ # @param end_at [Time, nil] Time after which any matching times will be skipped.
468
+ # @param jitter [Float, nil] Jitter to apply each action. An action's scheduled time will be incremented by a
469
+ # random value between 0 and this value if present (but not past the next schedule).
470
+ # @param time_zone_name [String, nil] IANA time zone name, for example `US/Central`.
471
+ def initialize(
472
+ calendars: [],
473
+ intervals: [],
474
+ cron_expressions: [],
475
+ skip: [],
476
+ start_at: nil,
477
+ end_at: nil,
478
+ jitter: nil,
479
+ time_zone_name: nil
480
+ )
481
+ super
482
+ end
483
+
484
+ # @!visibility private
485
+ def _to_proto
486
+ Api::Schedule::V1::ScheduleSpec.new(
487
+ structured_calendar: calendars.map(&:_to_proto),
488
+ cron_string: cron_expressions,
489
+ interval: intervals.map(&:_to_proto),
490
+ exclude_structured_calendar: skip.map(&:_to_proto),
491
+ start_time: Internal::ProtoUtils.time_to_timestamp(start_at),
492
+ end_time: Internal::ProtoUtils.time_to_timestamp(end_at),
493
+ jitter: Internal::ProtoUtils.seconds_to_duration(jitter),
494
+ timezone_name: time_zone_name || ''
495
+ )
496
+ end
497
+
498
+ Calendar = Data.define( # rubocop:disable Layout/ClassStructure
499
+ :second,
500
+ :minute,
501
+ :hour,
502
+ :day_of_month,
503
+ :month,
504
+ :year,
505
+ :day_of_week,
506
+ :comment
507
+ )
508
+
509
+ # Specification relative to calendar time when to run an action.
510
+ #
511
+ # A timestamp matches if at least one range of each field matches except for year. If year is missing, that
512
+ # means all years match. For all fields besides year, at least one range must be present to match anything.
513
+ #
514
+ # @!attribute second
515
+ # @return [Array<Range>] Second range to match, 0-59. Default matches 0.
516
+ # @!attribute minute
517
+ # @return [Array<Range>] Minute range to match, 0-59. Default matches 0.
518
+ # @!attribute hour
519
+ # @return [Array<Range>] Hour range to match, 0-23. Default matches 0.
520
+ # @!attribute day_of_month
521
+ # @return [Array<Range>] Day of month range to match, 1-31. Default matches all days.
522
+ # @!attribute month
523
+ # @return [Array<Range>] Month range to match, 1-12. Default matches all months.
524
+ # @!attribute year
525
+ # @return [Array<Range>] Optional year range to match. Default of empty matches all years.
526
+ # @!attribute day_of_week
527
+ # @return [Array<Range>] Day of week range to match, 0-6, 0 is Sunday. Default matches all days.
528
+ # @!attribute comment
529
+ # @return [String, nil] Description of this schedule.
530
+ class Calendar
531
+ # @!visibility private
532
+ def self._from_proto(raw_cal)
533
+ Calendar.new(
534
+ second: Range._from_protos(raw_cal.second),
535
+ minute: Range._from_protos(raw_cal.minute),
536
+ hour: Range._from_protos(raw_cal.hour),
537
+ day_of_month: Range._from_protos(raw_cal.day_of_month),
538
+ month: Range._from_protos(raw_cal.month),
539
+ year: Range._from_protos(raw_cal.year),
540
+ day_of_week: Range._from_protos(raw_cal.day_of_week),
541
+ comment: Internal::ProtoUtils.string_or(raw_cal.comment)
542
+ )
543
+ end
544
+
545
+ # Create a calendar spec.
546
+ #
547
+ # @param second [Array<Range>] Second range to match, 0-59. Default matches 0.
548
+ # @param minute [Array<Range>] Minute range to match, 0-59. Default matches 0.
549
+ # @param hour [Array<Range>] Hour range to match, 0-23. Default matches 0.
550
+ # @param day_of_month [Array<Range>] Day of month range to match, 1-31. Default matches all days.
551
+ # @param month [Array<Range>] Month range to match, 1-12. Default matches all months.
552
+ # @param year [Array<Range>] Optional year range to match. Default of empty matches all years.
553
+ # @param day_of_week [Array<Range>] Day of week range to match, 0-6, 0 is Sunday. Default matches all days.
554
+ # @param comment [String, nil] Description of this schedule.
555
+ def initialize(
556
+ second: [Range.new(0)],
557
+ minute: [Range.new(0)],
558
+ hour: [Range.new(0)],
559
+ day_of_month: [Range.new(1, 31)],
560
+ month: [Range.new(1, 12)],
561
+ year: [],
562
+ day_of_week: [Range.new(0, 6)],
563
+ comment: nil
564
+ )
565
+ super
566
+ end
567
+
568
+ # @!visibility private
569
+ def _to_proto
570
+ Api::Schedule::V1::StructuredCalendarSpec.new(
571
+ second: Range._to_protos(second),
572
+ minute: Range._to_protos(minute),
573
+ hour: Range._to_protos(hour),
574
+ day_of_month: Range._to_protos(day_of_month),
575
+ month: Range._to_protos(month),
576
+ year: Range._to_protos(year),
577
+ day_of_week: Range._to_protos(day_of_week),
578
+ comment: comment || ''
579
+ )
580
+ end
581
+ end
582
+
583
+ Interval = Data.define(
584
+ :every,
585
+ :offset
586
+ )
587
+
588
+ # Specification for scheduling on an interval.
589
+ #
590
+ # Matches times expressed as epoch + (n * every) + offset.
591
+ #
592
+ # @!attribute every
593
+ # @return [Float] Period to repeat the interval.
594
+ # @!attribute offset
595
+ # @return [Float, nil] Fixed offset added to each interval period.
596
+ class Interval
597
+ # @!visibility private
598
+ def self._from_proto(raw_int)
599
+ Schedule::Spec::Interval.new(
600
+ every: Internal::ProtoUtils.duration_to_seconds(raw_int.interval) || raise, # Never nil
601
+ offset: Internal::ProtoUtils.duration_to_seconds(raw_int.phase)
602
+ )
603
+ end
604
+
605
+ # Create an interval spec.
606
+ #
607
+ # @param every [Float] Period to repeat the interval.
608
+ # @param offset [Float, nil] Fixed offset added to each interval period.
609
+ def initialize(every:, offset: nil)
610
+ super
611
+ end
612
+
613
+ # @!visibility private
614
+ def _to_proto
615
+ Api::Schedule::V1::IntervalSpec.new(
616
+ interval: Internal::ProtoUtils.seconds_to_duration(every),
617
+ phase: Internal::ProtoUtils.seconds_to_duration(offset)
618
+ )
619
+ end
620
+ end
621
+ end
622
+
623
+ Range = Data.define(
624
+ :start,
625
+ :finish,
626
+ :step
627
+ )
628
+
629
+ # Inclusive range for a schedule match value.
630
+ #
631
+ # @!attribute start
632
+ # @return [Integer] Inclusive start of the range.
633
+ # @!attribute finish
634
+ # @return [Integer] Inclusive end of the range. If unset or less than start, defaults to start.
635
+ # @!attribute step
636
+ # @return [Integer] Step to take between each value. Defaults as 1.
637
+ class Range
638
+ class << self
639
+ alias _original_new new
640
+
641
+ # Create inclusive range.
642
+ #
643
+ # @param start [Integer] Inclusive start of the range.
644
+ # @param finish [Integer] Inclusive end of the range. If unset or less than start, defaults to start.
645
+ # @param step [Integer] Step to take between each value. Defaults as 1.
646
+ def new(start, finish = [0, start].max, step = 1)
647
+ _original_new( # steep:ignore
648
+ start:,
649
+ finish:,
650
+ step:
651
+ )
652
+ end
653
+ end
654
+
655
+ # @!visibility private
656
+ def self._from_proto(raw_range)
657
+ Schedule::Range.new(
658
+ raw_range.start,
659
+ raw_range.end,
660
+ raw_range.step
661
+ )
662
+ end
663
+
664
+ # @!visibility private
665
+ def self._from_protos(raw_ranges)
666
+ raw_ranges.map { |v| _from_proto(v) }
667
+ end
668
+
669
+ # @!visibility private
670
+ def self._to_protos(ranges)
671
+ ranges.map(&:_to_proto)
672
+ end
673
+
674
+ # @!visibility private
675
+ def _to_proto
676
+ Api::Schedule::V1::Range.new(
677
+ start:,
678
+ end: finish,
679
+ step:
680
+ )
681
+ end
682
+ end
683
+
684
+ Policy = Data.define(
685
+ :overlap,
686
+ :catchup_window,
687
+ :pause_on_failure
688
+ )
689
+
690
+ # Policies of a schedule.
691
+ #
692
+ # @!attribute overlap
693
+ # @return [OverlapPolicy] Controls what happens when an action is started while another is still running.
694
+ # @!attribute catchup_window
695
+ # @return [Float] After a Temporal server is unavailable, amount of time in the past to execute missed actions.
696
+ # @!attribute pause_on_failure
697
+ # @return [Boolean] Whether to pause the schedule if an action fails or times out. Note: For workflows, this
698
+ # only applies after all retries have been exhausted.
699
+ class Policy
700
+ # @!visibility private
701
+ def self._from_proto(raw_policies)
702
+ Schedule::Policy.new(
703
+ overlap: Internal::ProtoUtils.enum_to_int(Api::Enums::V1::ScheduleOverlapPolicy,
704
+ raw_policies.overlap_policy,
705
+ zero_means_nil: true),
706
+ catchup_window: Internal::ProtoUtils.duration_to_seconds(raw_policies.catchup_window) || raise, # Never nil
707
+ pause_on_failure: raw_policies.pause_on_failure
708
+ )
709
+ end
710
+
711
+ # Create a schedule policy.
712
+ #
713
+ # @param overlap [OverlapPolicy] Controls what happens when an action is started while another is still running.
714
+ # @param catchup_window [Float] After a Temporal server is unavailable, amount of time in the past to execute
715
+ # missed actions.
716
+ # @param pause_on_failure [Boolean] Whether to pause the schedule if an action fails or times out. Note: For
717
+ # workflows, this only applies after all retries have been exhausted.
718
+ def initialize(
719
+ overlap: OverlapPolicy::SKIP,
720
+ catchup_window: 365 * 24 * 60 * 60.0,
721
+ pause_on_failure: false
722
+ )
723
+ super
724
+ end
725
+
726
+ # @!visibility private
727
+ def _to_proto
728
+ Api::Schedule::V1::SchedulePolicies.new(
729
+ overlap_policy: overlap,
730
+ catchup_window: Internal::ProtoUtils.seconds_to_duration(catchup_window),
731
+ pause_on_failure:
732
+ )
733
+ end
734
+ end
735
+
736
+ State = Data.define(
737
+ :note,
738
+ :paused,
739
+ :limited_actions,
740
+ :remaining_actions
741
+ )
742
+
743
+ # State of a schedule.
744
+ #
745
+ # @!attribute note
746
+ # @return [String, nil] Human readable message for the schedule. The system may overwrite this value on certain
747
+ # conditions like pause-on-failure.
748
+ # @!attribute paused
749
+ # @return [Boolean] Whether the schedule is paused.
750
+ # @!attribute limited_actions
751
+ # @return [Boolean] If true, remaining actions will be decremented for each action taken. On schedule create,
752
+ # this must be set to true if `remaining_actions` is non-zero and left false if `remaining_actions` is zero.
753
+ # @!attribute remaining_actions
754
+ # @return [Integer] Actions remaining on this schedule. Once this number hits 0, no further actions are
755
+ # scheduled automatically.
756
+ class State
757
+ # @!visibility private
758
+ def self._from_proto(raw_state)
759
+ Schedule::State.new(
760
+ note: Internal::ProtoUtils.string_or(raw_state.notes),
761
+ paused: raw_state.paused,
762
+ limited_actions: raw_state.limited_actions,
763
+ remaining_actions: raw_state.remaining_actions
764
+ )
765
+ end
766
+
767
+ # Create a schedule state.
768
+ #
769
+ # @param note [String, nil] Human readable message for the schedule. The system may overwrite this value on
770
+ # certain conditions like pause-on-failure.
771
+ # @param paused [Boolean] Whether the schedule is paused.
772
+ # @param limited_actions [Boolean] If true, remaining actions will be decremented for each action taken. On
773
+ # schedule create, this must be set to true if `remaining_actions` is non-zero and left false if
774
+ # `remaining_actions` is zero.
775
+ # @param remaining_actions [Integer] Actions remaining on this schedule. Once this number hits 0, no further
776
+ # actions are scheduled automatically.
777
+ def initialize(
778
+ note: nil,
779
+ paused: false,
780
+ limited_actions: false,
781
+ remaining_actions: 0
782
+ )
783
+ super
784
+ end
785
+
786
+ # @!visibility private
787
+ def _to_proto
788
+ Api::Schedule::V1::ScheduleState.new(
789
+ notes: note || '',
790
+ paused:,
791
+ limited_actions:,
792
+ remaining_actions:
793
+ )
794
+ end
795
+ end
796
+
797
+ Update = Data.define(
798
+ :schedule,
799
+ :search_attributes
800
+ )
801
+
802
+ # Result of an update callback for {ScheduleHandle.update}.
803
+ #
804
+ # @!attribute schedule
805
+ # @return [Schedule] Schedule to update.
806
+ # @!attribute search_attributes
807
+ # @return [SearchAttributes, nil] Search attributes to update to.
808
+ class Update
809
+ # Create an update callback result.
810
+ #
811
+ # @param schedule [Schedule] Schedule to update.
812
+ # @param search_attributes [SearchAttributes, nil] Search attributes to update to.
813
+ def initialize(schedule:, search_attributes: nil)
814
+ super
815
+ end
816
+
817
+ # Parameter for an update callback for {ScheduleHandle.update}.
818
+ #
819
+ # @!attribute description
820
+ # @return [Description] Current description of the schedule.
821
+ Input = Data.define( # rubocop:disable Layout/ClassStructure
822
+ :description
823
+ )
824
+ end
825
+
826
+ module List
827
+ Description = Data.define(
828
+ :id,
829
+ :schedule,
830
+ :info,
831
+ :raw_entry
832
+ )
833
+
834
+ # Description of a listed schedule.
835
+ #
836
+ # @!attribute id
837
+ # @return [String] ID of the schedule.
838
+ # @!attribute schedule
839
+ # @return [Schedule, nil] Schedule details that can be mutated. This may not be present in older Temporal
840
+ # servers without advanced visibility.
841
+ # @!attribute info
842
+ # @return [Info, nil] Information about the schedule. This may not be present in older Temporal servers
843
+ # without advanced visibility.
844
+ # @!attribute raw_entry
845
+ # @return [Api::Schedule::V1::ScheduleListEntry] Raw description of the schedule.
846
+ class Description
847
+ # @!visibility private
848
+ def initialize(raw_entry:, data_converter:)
849
+ @memo = Internal::ProtoUtils::LazyMemo.new(raw_entry.memo, data_converter)
850
+ @search_attributes = Internal::ProtoUtils::LazySearchAttributes.new(raw_entry.search_attributes)
851
+ # steep:ignore:start
852
+ super(
853
+ id: raw_entry.schedule_id,
854
+ schedule: (Schedule.new(raw_info: raw_entry.info) if raw_entry.info),
855
+ info: (Info.new(raw_info: raw_entry.info) if raw_entry.info),
856
+ raw_entry:
857
+ )
858
+ # steep:ignore:end
859
+ end
860
+
861
+ # @return [Hash<String, Object>, nil] Memo for the schedule, converted lazily on first call.
862
+ def memo
863
+ @memo.get
864
+ end
865
+
866
+ # @return [Search attributes, nil] Search attributes for the schedule, converted lazily on first call.
867
+ def search_attributes
868
+ @search_attributes.get
869
+ end
870
+ end
871
+
872
+ Schedule = Data.define(
873
+ :action,
874
+ :spec,
875
+ :state
876
+ )
877
+
878
+ # Details for a listed schedule.
879
+ #
880
+ # @!attribute action
881
+ # @return [Action] Action taken when scheduled.
882
+ # @!attribute spec
883
+ # @return [Spec] When the action is taken.
884
+ # @!attribute state
885
+ # @return [State] State of the schedule.
886
+ class Schedule
887
+ # @!visibility private
888
+ def initialize(raw_info:)
889
+ raise 'Unknown action on schedule' unless raw_info.workflow_type
890
+
891
+ # steep:ignore:start
892
+ super(
893
+ action: Action::StartWorkflow.new(workflow: raw_info.workflow_type.name),
894
+ spec: Spec._from_proto(raw_info.spec),
895
+ state: State.new(raw_info:)
896
+ )
897
+ # steep:ignore:end
898
+ end
899
+ end
900
+
901
+ # Base module mixed in by specific actions a listed schedule can take.
902
+ module Action
903
+ StartWorkflow = Data.define(
904
+ :workflow
905
+ )
906
+
907
+ # Action to start a workflow on a listed schedule.
908
+ #
909
+ # @!attribute workflow
910
+ # @return [String] Workflow type name.
911
+ class StartWorkflow
912
+ include Action
913
+ end
914
+ end
915
+
916
+ Info = Data.define(
917
+ :recent_actions,
918
+ :next_action_times
919
+ )
920
+
921
+ # Information about a listed schedule.
922
+ #
923
+ # @!attribute recent_actions
924
+ # @return [Array<ActionResult>] Most recent actions, oldest first. This may be a smaller amount than present
925
+ # on {Temporalio::Client::Schedule::Info.recent_actions}.
926
+ # @!attribute next_action_times
927
+ # @return [Array<Time>] Next scheduled action times. This may be a smaller amount than present on
928
+ # {Temporalio::Client::Schedule::Info.next_action_times}.
929
+ class Info
930
+ # @!visibility private
931
+ def initialize(raw_info:)
932
+ # steep:ignore:start
933
+ super(
934
+ recent_actions: raw_info.recent_actions.map { |a| ActionResult.new(raw_result: a) },
935
+ next_action_times: raw_info.future_action_times.map { |t| Internal::ProtoUtils.timestamp_to_time(t) }
936
+ )
937
+ # steep:ignore:end
938
+ end
939
+ end
940
+
941
+ State = Data.define(
942
+ :note,
943
+ :paused
944
+ )
945
+
946
+ # State of a listed schedule.
947
+ #
948
+ # @!attribute note
949
+ # @return [String, nil] Human readable message for the schedule. The system may overwrite this value on
950
+ # certain conditions like pause-on-failure.
951
+ # @!attribute paused
952
+ # @return [Boolean] Whether the schedule is paused.
953
+ class State
954
+ # @!visibility private
955
+ def initialize(raw_info:)
956
+ # steep:ignore:start
957
+ super(
958
+ note: Internal::ProtoUtils.string_or(raw_info.notes),
959
+ paused: raw_info.paused
960
+ )
961
+ # steep:ignore:end
962
+ end
963
+ end
964
+ end
965
+ end
966
+ end
967
+ end