temporalio 1.7.0-x86_64-linux → 1.8.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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +19 -0
  3. data/lib/temporalio/client/activity_execution.rb +82 -1
  4. data/lib/temporalio/client/activity_execution_options.rb +39 -0
  5. data/lib/temporalio/client/activity_execution_status.rb +1 -0
  6. data/lib/temporalio/client/activity_handle.rb +122 -1
  7. data/lib/temporalio/client/activity_options.rb +113 -0
  8. data/lib/temporalio/client/interceptor.rb +65 -0
  9. data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
  10. data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
  11. data/lib/temporalio/internal/bridge/4.0/temporalio_bridge.so +0 -0
  12. data/lib/temporalio/internal/client/implementation.rb +54 -2
  13. data/lib/temporalio/scoped_logger.rb +3 -0
  14. data/lib/temporalio/version.rb +1 -1
  15. data/lib/temporalio/worker/activity_executor/fiber.rb +11 -1
  16. data/rbi/temporalio/client/activity_execution.rbi +27 -0
  17. data/rbi/temporalio/client/activity_execution_options.rbi +58 -0
  18. data/rbi/temporalio/client/activity_execution_status.rbi +1 -0
  19. data/rbi/temporalio/client/activity_handle.rbi +43 -2
  20. data/rbi/temporalio/client/activity_options.rbi +49 -0
  21. data/rbi/temporalio/client/interceptor.rbi +107 -0
  22. data/sig/temporalio/client/activity_execution.rbs +10 -0
  23. data/sig/temporalio/client/activity_execution_options.rbs +27 -0
  24. data/sig/temporalio/client/activity_execution_status.rbs +1 -0
  25. data/sig/temporalio/client/activity_handle.rbs +23 -1
  26. data/sig/temporalio/client/activity_options.rbs +30 -0
  27. data/sig/temporalio/client/interceptor.rbs +62 -0
  28. data/sig/temporalio/internal/client/implementation.rbs +7 -0
  29. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf8eb367ec609eb27a2532584c08900bb6ddb83c9e557a4e0b56f4ebce771315
4
- data.tar.gz: b7c440941d105ffb8777b0c14a5c98246e9acb490cfa44e709577e7edc1115a8
3
+ metadata.gz: 9c8d32b494a1d9b5783705d25806b2344eea22a0215b5bae6cc1d50fa46e9b2f
4
+ data.tar.gz: 00772da1220ca6a4c3808f0d372c8674e7465c0e725ad7ae4d9bfb5b473d7be4
5
5
  SHA512:
6
- metadata.gz: 077d14a59deac377895e790cce96e284fb00b4e2c5eb7dc9f77a28e9ecc17b38d5e31a0ca0feb8f61def330c7d5d75c0e1542460b6a55a8a750647bef31c0595
7
- data.tar.gz: 286d6d7a4ac4e97de19725f63a5f4bf20e8eda52c44918c0f0ec274e5528f889ae92101068e6196c72baac0f0119da188d9cfe124515d0af59e4ea1f799ea2cd
6
+ metadata.gz: a8556bdbe97f3c82dfe673b9896e8de669f7f89c4b859fd66ba02f5bc9dabc7e135168939b0a0f3f51cf0e02f53023562d2df5d3c44fa2059adf9aa5942493cc
7
+ data.tar.gz: f20a985e37fe1fcb76a34de2a6a7706c602caba82eb166d66e47d887af7fa40f307bbf0356b4743bd28bc6bf16eb9caba6f7524e9b13da0c1ff9f8a762e1c6c7
data/Rakefile CHANGED
@@ -27,6 +27,25 @@ Rake::TestTask.new(:test) do |t|
27
27
  t.test_files = FileList['test/**/*_test.rb', 'extra/release/test/**/*_test.rb']
28
28
  end
29
29
 
30
+ namespace :test do
31
+ desc 'List tests excluded from Temporal Cloud by reason'
32
+ task :cloud_inventory do
33
+ ENV['TESTOPTS'] = [
34
+ ENV.fetch('TESTOPTS', nil),
35
+ '--cloud-inventory',
36
+ '--name=/CloudTestInventoryTest#test_report/'
37
+ ].compact.join(' ')
38
+ Rake::Task[:test].invoke
39
+ end
40
+
41
+ desc 'Run tests eligible for Temporal Cloud using envconfig'
42
+ task :cloud do
43
+ ENV['TEMPORAL_TEST_ENV_CONFIG_SERVER'] = '1'
44
+ ENV['TESTOPTS'] = [ENV.fetch('TESTOPTS', nil), '--cloud'].compact.join(' ')
45
+ Rake::Task[:test].invoke
46
+ end
47
+ end
48
+
30
49
  require 'rubocop/rake_task'
31
50
 
32
51
  RuboCop::RakeTask.new
@@ -46,6 +46,12 @@ module Temporalio
46
46
  Internal::ProtoUtils.timestamp_to_time(@raw_info.schedule_time)
47
47
  end
48
48
 
49
+ # @return [Time, nil] When the first activity task was made available for dispatch. Equals
50
+ # schedule_time + start_delay; equal to schedule_time when no start delay is set.
51
+ def execution_time
52
+ Internal::ProtoUtils.timestamp_to_time(@raw_info.execution_time)
53
+ end
54
+
49
55
  # @return [Time, nil] When the activity reached a terminal state.
50
56
  def close_time
51
57
  Internal::ProtoUtils.timestamp_to_time(@raw_info.close_time)
@@ -112,7 +118,17 @@ module Temporalio
112
118
  Internal::ProtoUtils.duration_to_seconds(@raw_info.heartbeat_timeout)
113
119
  end
114
120
 
115
- # @return [Boolean] Whether the activity has recorded any heartbeat details.
121
+ # @return [Float, nil] Delay in seconds before the first activity task is made available for
122
+ # dispatch. Not applied to retry attempts.
123
+ def start_delay
124
+ Internal::ProtoUtils.duration_to_seconds(@raw_info.start_delay)
125
+ end
126
+
127
+ # Whether heartbeat details are present on this description. False when the activity
128
+ # recorded none, and also when {ActivityHandle#describe} was called without
129
+ # `include_heartbeat_details:`.
130
+ #
131
+ # @return [Boolean] Whether heartbeat details are present.
116
132
  def has_heartbeat_details? # rubocop:disable Naming/PredicatePrefix
117
133
  !@raw_info.heartbeat_details&.payloads.nil? && !@raw_info.heartbeat_details.payloads.empty?
118
134
  end
@@ -125,6 +141,57 @@ module Temporalio
125
141
  @data_converter.from_payloads(@raw_info.heartbeat_details, hints:)
126
142
  end
127
143
 
144
+ # Whether the activity's input is present. False unless {ActivityHandle#describe} was
145
+ # called with `include_input:`.
146
+ #
147
+ # @return [Boolean] Whether input is present.
148
+ def has_input? # rubocop:disable Naming/PredicatePrefix
149
+ !@raw_description.input.nil?
150
+ end
151
+
152
+ # Deserialized activity input, one element per argument. Empty when no input is present.
153
+ #
154
+ # @param hints [Array<Object>, nil] Hints, if any, to assist conversion.
155
+ # @return [Array<Object>] Converted arguments.
156
+ def input(hints: nil)
157
+ @data_converter.from_payloads(@raw_description.input, hints:)
158
+ end
159
+
160
+ # Whether the activity closed with a successful result. False while the activity is still
161
+ # running, when it closed with a failure, and when {ActivityHandle#describe} was called
162
+ # without `include_outcome:`.
163
+ #
164
+ # @return [Boolean] Whether a result is present.
165
+ def has_result? # rubocop:disable Naming/PredicatePrefix
166
+ @raw_description.outcome&.value == :result
167
+ end
168
+
169
+ # Deserialized result the activity closed with. Nil when no result is present (still
170
+ # running, closed with a failure, or `include_outcome:` was not requested).
171
+ #
172
+ # @param result_hint [Object, nil] Hint, if any, to assist conversion.
173
+ # @return [Object, nil] Converted result.
174
+ def result(result_hint: nil)
175
+ return nil unless has_result?
176
+
177
+ @data_converter.from_payloads(
178
+ @raw_description.outcome.result, hints: Array(result_hint)
179
+ ).first
180
+ end
181
+
182
+ # Failure the activity closed with. Nil when the activity did not close with a failure or
183
+ # when {ActivityHandle#describe} was called without `include_outcome:`.
184
+ #
185
+ # This is the terminal outcome; {#last_failure} is the failure of the most recent attempt,
186
+ # which may be set while the activity is still retrying.
187
+ #
188
+ # @return [Error::Failure, nil] Converted failure.
189
+ def failure
190
+ return nil unless @raw_description.outcome&.value == :failure
191
+
192
+ @data_converter.from_failure(@raw_description.outcome.failure)
193
+ end
194
+
128
195
  # @return [RetryPolicy] Retry policy in effect for this activity.
129
196
  def retry_policy
130
197
  RetryPolicy._from_proto(@raw_info.retry_policy)
@@ -145,6 +212,20 @@ module Temporalio
145
212
  @raw_info.attempt
146
213
  end
147
214
 
215
+ # @return [Integer] Total number of heartbeats recorded across all attempts.
216
+ def total_heartbeat_count
217
+ @raw_info.total_heartbeat_count
218
+ end
219
+
220
+ # Whether a last failure is present on this description. False when the activity has no
221
+ # failed attempt, and also when {ActivityHandle#describe} was called without
222
+ # `include_last_failure:`.
223
+ #
224
+ # @return [Boolean] Whether a last failure is present.
225
+ def has_last_failure? # rubocop:disable Naming/PredicatePrefix
226
+ !@raw_info.last_failure.nil?
227
+ end
228
+
148
229
  # @return [Error::Failure, nil] Failure of the last failed attempt if any.
149
230
  def last_failure
150
231
  return nil unless @raw_info.last_failure
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/internal/proto_utils'
4
+ require 'temporalio/priority'
5
+ require 'temporalio/retry_policy'
6
+
7
+ module Temporalio
8
+ class Client
9
+ # The resolved options of a standalone activity execution, as returned by
10
+ # {ActivityHandle#update_options}. Reflects the activity's options as the server resolved them
11
+ # after the update was applied.
12
+ #
13
+ # WARNING: Standalone Activities are experimental.
14
+ ActivityExecutionOptions = Data.define(
15
+ :task_queue,
16
+ :schedule_to_close_timeout,
17
+ :schedule_to_start_timeout,
18
+ :start_to_close_timeout,
19
+ :heartbeat_timeout,
20
+ :retry_policy,
21
+ :priority,
22
+ :start_delay
23
+ ) do
24
+ # @!visibility private
25
+ def self._from_proto(options)
26
+ new(
27
+ task_queue: Internal::ProtoUtils.string_or(options.task_queue&.name, nil),
28
+ schedule_to_close_timeout: Internal::ProtoUtils.duration_to_seconds(options.schedule_to_close_timeout),
29
+ schedule_to_start_timeout: Internal::ProtoUtils.duration_to_seconds(options.schedule_to_start_timeout),
30
+ start_to_close_timeout: Internal::ProtoUtils.duration_to_seconds(options.start_to_close_timeout),
31
+ heartbeat_timeout: Internal::ProtoUtils.duration_to_seconds(options.heartbeat_timeout),
32
+ retry_policy: options.retry_policy ? RetryPolicy._from_proto(options.retry_policy) : nil,
33
+ priority: Priority._from_proto(options.priority),
34
+ start_delay: Internal::ProtoUtils.duration_to_seconds(options.start_delay)
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
@@ -15,6 +15,7 @@ module Temporalio
15
15
  CANCELED = Api::Enums::V1::ActivityExecutionStatus::ACTIVITY_EXECUTION_STATUS_CANCELED
16
16
  TERMINATED = Api::Enums::V1::ActivityExecutionStatus::ACTIVITY_EXECUTION_STATUS_TERMINATED
17
17
  TIMED_OUT = Api::Enums::V1::ActivityExecutionStatus::ACTIVITY_EXECUTION_STATUS_TIMED_OUT
18
+ PAUSED = Api::Enums::V1::ActivityExecutionStatus::ACTIVITY_EXECUTION_STATUS_PAUSED
18
19
  end
19
20
  end
20
21
  end
@@ -2,8 +2,13 @@
2
2
 
3
3
  require 'temporalio/api'
4
4
  require 'temporalio/client/activity_execution'
5
+ require 'temporalio/client/activity_execution_options'
6
+ require 'temporalio/client/activity_options'
5
7
  require 'temporalio/client/interceptor'
6
8
  require 'temporalio/error'
9
+ require 'temporalio/internal/proto_utils'
10
+ require 'temporalio/priority'
11
+ require 'temporalio/retry_policy'
7
12
 
8
13
  module Temporalio
9
14
  class Client
@@ -55,15 +60,35 @@ module Temporalio
55
60
 
56
61
  # Describe the activity.
57
62
  #
63
+ # The payload-bearing fields are opt-in because they can be arbitrarily large; request them
64
+ # only when needed. Each has a corresponding predicate on the returned description that
65
+ # reports whether the server supplied it.
66
+ #
67
+ # @param include_input [Boolean] If true and the activity received input, include the input.
68
+ # @param include_outcome [Boolean] If true and the activity is closed, include the outcome.
69
+ # @param include_heartbeat_details [Boolean] If true and the activity recorded heartbeat
70
+ # details, include them.
71
+ # @param include_last_failure [Boolean] If true and the activity has a failed attempt, include
72
+ # the last failure.
58
73
  # @param rpc_options [RPCOptions, nil] Advanced RPC options.
59
74
  #
60
75
  # @return [ActivityExecution::Description] Activity description.
61
76
  # @raise [Error::RPCError] RPC error from call.
62
- def describe(rpc_options: nil)
77
+ def describe(
78
+ include_input: false,
79
+ include_outcome: false,
80
+ include_heartbeat_details: false,
81
+ include_last_failure: false,
82
+ rpc_options: nil
83
+ )
63
84
  @client._impl.describe_activity(
64
85
  Interceptor::DescribeActivityInput.new(
65
86
  activity_id: id,
66
87
  activity_run_id: run_id,
88
+ include_input:,
89
+ include_outcome:,
90
+ include_heartbeat_details:,
91
+ include_last_failure:,
67
92
  rpc_options:
68
93
  )
69
94
  )
@@ -103,6 +128,102 @@ module Temporalio
103
128
  nil
104
129
  end
105
130
 
131
+ # Pause the activity. A paused activity is not scheduled or retried until it is unpaused via
132
+ # {#unpause}.
133
+ #
134
+ # WARNING: Standalone Activities are experimental.
135
+ #
136
+ # @param reason [String, nil] Optional reason recorded on the server.
137
+ # @param rpc_options [RPCOptions, nil] Advanced RPC options.
138
+ # @raise [Error::RPCError] RPC error from call.
139
+ def pause(reason = nil, rpc_options: nil)
140
+ @client._impl.pause_activity(
141
+ Interceptor::PauseActivityInput.new(
142
+ activity_id: id,
143
+ activity_run_id: run_id,
144
+ reason:,
145
+ rpc_options:
146
+ )
147
+ )
148
+ nil
149
+ end
150
+
151
+ # Unpause the activity, allowing it to be scheduled or retried again.
152
+ #
153
+ # WARNING: Standalone Activities are experimental.
154
+ #
155
+ # @param reason [String, nil] Optional reason recorded on the server.
156
+ # @param jitter [Float, nil] If set, the activity will start at a random time within this
157
+ # duration (in seconds).
158
+ # @param rpc_options [RPCOptions, nil] Advanced RPC options.
159
+ # @raise [Error::RPCError] RPC error from call.
160
+ def unpause(reason: nil, jitter: nil, rpc_options: nil)
161
+ @client._impl.unpause_activity(
162
+ Interceptor::UnpauseActivityInput.new(
163
+ activity_id: id,
164
+ activity_run_id: run_id,
165
+ reason:,
166
+ jitter:,
167
+ rpc_options:
168
+ )
169
+ )
170
+ nil
171
+ end
172
+
173
+ # Update the activity's options. Only the options named by `updates` are changed; anything
174
+ # not named is left as-is.
175
+ #
176
+ # Updates are created from the keys on {ActivityOptions}, via {ActivityOptions::Key#value_set}
177
+ # to set an option or {ActivityOptions::Key#value_unset} to clear it.
178
+ #
179
+ # WARNING: Standalone Activities are experimental.
180
+ #
181
+ # @param updates [Array<ActivityOptions::Update>] The option updates to apply. At least one is
182
+ # required unless `restore_original` is true.
183
+ # @param restore_original [Boolean] If true, restore the options to the originals the activity
184
+ # was created with. Mutually exclusive with any update.
185
+ # @param rpc_options [RPCOptions, nil] Advanced RPC options.
186
+ #
187
+ # @return [ActivityExecutionOptions] The activity options after the update.
188
+ #
189
+ # @raise [ArgumentError] If a non-update is given, if `restore_original` is combined with any
190
+ # update, or if no update is provided and `restore_original` is false.
191
+ # @raise [Error::RPCError] RPC error from call.
192
+ def update_options(*updates, restore_original: false, rpc_options: nil)
193
+ unless updates.all?(ActivityOptions::Update)
194
+ raise ArgumentError,
195
+ 'Updates must be created via ActivityOptions::Key#value_set or #value_unset'
196
+ end
197
+
198
+ if restore_original && !updates.empty?
199
+ raise ArgumentError, 'restore_original cannot be combined with any option update'
200
+ elsif !restore_original && updates.empty?
201
+ raise ArgumentError,
202
+ 'At least one option update must be given, or restore_original must be used'
203
+ end
204
+
205
+ # For repeated keys, later values override previous ones.
206
+ by_path = updates.to_h { |update| [update.key.name, update] }
207
+
208
+ proto = Api::Activity::V1::ActivityOptions.new
209
+ by_path.each_value do |update|
210
+ # An unset update names its path but leaves the field absent, which is how the server is
211
+ # told to clear the option rather than set it to a value.
212
+ update.key._apply(proto, update.value) unless update.value.nil?
213
+ end
214
+
215
+ @client._impl.update_activity_options(
216
+ Interceptor::UpdateActivityOptionsInput.new(
217
+ activity_id: id,
218
+ activity_run_id: run_id,
219
+ activity_options: proto,
220
+ update_mask: Google::Protobuf::FieldMask.new(paths: by_path.keys),
221
+ restore_original:,
222
+ rpc_options:
223
+ )
224
+ )
225
+ end
226
+
106
227
  private
107
228
 
108
229
  def _process_outcome(outcome, hint)
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/api'
4
+ require 'temporalio/internal/proto_utils'
5
+
6
+ module Temporalio
7
+ class Client
8
+ # The activity options that {ActivityHandle#update_options} can change.
9
+ #
10
+ # Updates are created from the keys below, via {Key#value_set} to set an option or
11
+ # {Key#value_unset} to clear it. An option with no update is left untouched.
12
+ #
13
+ # WARNING: Standalone Activities are experimental.
14
+ module ActivityOptions
15
+ # Typed key for one updatable activity option. Use the keys on {ActivityOptions} rather than
16
+ # constructing these directly.
17
+ class Key
18
+ # @return [String] Field-mask path this key updates.
19
+ attr_reader :name
20
+
21
+ # @!visibility private
22
+ def initialize(name, &to_proto)
23
+ @name = name
24
+ @to_proto = to_proto
25
+ freeze
26
+ end
27
+
28
+ # Create an update that sets this option to the given value.
29
+ #
30
+ # @param value [Object] Value to set. Cannot be nil.
31
+ # @return [Update] Created update.
32
+ def value_set(value)
33
+ raise ArgumentError, 'Value cannot be nil, use value_unset' if value.nil?
34
+
35
+ Update.new(self, value)
36
+ end
37
+
38
+ # Create an update that clears this option server-side.
39
+ #
40
+ # @return [Update] Created update.
41
+ def value_unset
42
+ Update.new(self, nil)
43
+ end
44
+
45
+ # @!visibility private
46
+ def _apply(proto, value)
47
+ @to_proto.call(proto, value)
48
+ end
49
+ end
50
+
51
+ # A single change to an activity's options that can be separately applied.
52
+ class Update
53
+ # @return [Key] Key this update applies to.
54
+ attr_reader :key
55
+
56
+ # @return [Object, nil] Value to set, or `nil` to clear the option.
57
+ attr_reader :value
58
+
59
+ # Create an update. Users may find it easier to use {Key#value_set} and {Key#value_unset}.
60
+ #
61
+ # @param key [Key] Key to update.
62
+ # @param value [Object, nil] Value to set, or nil to clear the option.
63
+ def initialize(key, value)
64
+ raise ArgumentError, 'Key must be a key' unless key.is_a?(Key)
65
+
66
+ @key = key
67
+ @value = value
68
+ freeze
69
+ end
70
+ end
71
+
72
+ # @return [Key] New task queue.
73
+ TASK_QUEUE = Key.new('task_queue.name') do |proto, value|
74
+ proto.task_queue = Api::TaskQueue::V1::TaskQueue.new(name: value.to_s)
75
+ end
76
+
77
+ # @return [Key] New schedule-to-close timeout in seconds.
78
+ SCHEDULE_TO_CLOSE_TIMEOUT = Key.new('schedule_to_close_timeout') do |proto, value|
79
+ proto.schedule_to_close_timeout = Internal::ProtoUtils.seconds_to_duration(value)
80
+ end
81
+
82
+ # @return [Key] New schedule-to-start timeout in seconds.
83
+ SCHEDULE_TO_START_TIMEOUT = Key.new('schedule_to_start_timeout') do |proto, value|
84
+ proto.schedule_to_start_timeout = Internal::ProtoUtils.seconds_to_duration(value)
85
+ end
86
+
87
+ # @return [Key] New start-to-close timeout in seconds.
88
+ START_TO_CLOSE_TIMEOUT = Key.new('start_to_close_timeout') do |proto, value|
89
+ proto.start_to_close_timeout = Internal::ProtoUtils.seconds_to_duration(value)
90
+ end
91
+
92
+ # @return [Key] New heartbeat timeout in seconds.
93
+ HEARTBEAT_TIMEOUT = Key.new('heartbeat_timeout') do |proto, value|
94
+ proto.heartbeat_timeout = Internal::ProtoUtils.seconds_to_duration(value)
95
+ end
96
+
97
+ # @return [Key] New start delay in seconds.
98
+ START_DELAY = Key.new('start_delay') do |proto, value|
99
+ proto.start_delay = Internal::ProtoUtils.seconds_to_duration(value)
100
+ end
101
+
102
+ # @return [Key] New retry policy.
103
+ RETRY_POLICY = Key.new('retry_policy') do |proto, value|
104
+ proto.retry_policy = value._to_proto
105
+ end
106
+
107
+ # @return [Key] New priority.
108
+ PRIORITY = Key.new('priority') do |proto, value|
109
+ proto.priority = value._to_proto
110
+ end
111
+ end
112
+ end
113
+ end
@@ -291,6 +291,10 @@ module Temporalio
291
291
  DescribeActivityInput = Data.define(
292
292
  :activity_id,
293
293
  :activity_run_id,
294
+ :include_input,
295
+ :include_outcome,
296
+ :include_heartbeat_details,
297
+ :include_last_failure,
294
298
  :rpc_options
295
299
  )
296
300
 
@@ -314,6 +318,39 @@ module Temporalio
314
318
  :rpc_options
315
319
  )
316
320
 
321
+ # Input for {Outbound.pause_activity}.
322
+ #
323
+ # WARNING: Standalone Activities are experimental.
324
+ PauseActivityInput = Data.define(
325
+ :activity_id,
326
+ :activity_run_id,
327
+ :reason,
328
+ :rpc_options
329
+ )
330
+
331
+ # Input for {Outbound.unpause_activity}.
332
+ #
333
+ # WARNING: Standalone Activities are experimental.
334
+ UnpauseActivityInput = Data.define(
335
+ :activity_id,
336
+ :activity_run_id,
337
+ :reason,
338
+ :jitter,
339
+ :rpc_options
340
+ )
341
+
342
+ # Input for {Outbound.update_activity_options}.
343
+ #
344
+ # WARNING: Standalone Activities are experimental.
345
+ UpdateActivityOptionsInput = Data.define(
346
+ :activity_id,
347
+ :activity_run_id,
348
+ :activity_options,
349
+ :update_mask,
350
+ :restore_original,
351
+ :rpc_options
352
+ )
353
+
317
354
  # Input for {Outbound.list_activities}.
318
355
  #
319
356
  # WARNING: Standalone Activities are experimental.
@@ -587,6 +624,34 @@ module Temporalio
587
624
  next_interceptor.terminate_activity(input)
588
625
  end
589
626
 
627
+ # Called for every {ActivityHandle.pause} call.
628
+ #
629
+ # WARNING: Standalone Activities are experimental.
630
+ #
631
+ # @param input [PauseActivityInput] Input.
632
+ def pause_activity(input)
633
+ next_interceptor.pause_activity(input)
634
+ end
635
+
636
+ # Called for every {ActivityHandle.unpause} call.
637
+ #
638
+ # WARNING: Standalone Activities are experimental.
639
+ #
640
+ # @param input [UnpauseActivityInput] Input.
641
+ def unpause_activity(input)
642
+ next_interceptor.unpause_activity(input)
643
+ end
644
+
645
+ # Called for every {ActivityHandle.update_options} call.
646
+ #
647
+ # WARNING: Standalone Activities are experimental.
648
+ #
649
+ # @param input [UpdateActivityOptionsInput] Input.
650
+ # @return [Api::Activity::V1::ActivityOptions] Activity options after the update.
651
+ def update_activity_options(input)
652
+ next_interceptor.update_activity_options(input)
653
+ end
654
+
590
655
  # Called for every {Client.list_activities} call.
591
656
  #
592
657
  # WARNING: Standalone Activities are experimental.
@@ -29,7 +29,7 @@ require 'temporalio/workflow/definition'
29
29
  module Temporalio
30
30
  module Internal
31
31
  module Client
32
- class Implementation < Temporalio::Client::Interceptor::Outbound
32
+ class Implementation < Temporalio::Client::Interceptor::Outbound # rubocop:disable Metrics/ClassLength
33
33
  # Proto routing convention for standalone activity completion: `*_by_id` requests carry
34
34
  # `resource_id = "activity:<activity_id>"`. See the resource_id field comment on
35
35
  # `RecordActivityTaskHeartbeatByIdRequest` (and the analogous Completed/Failed/Canceled
@@ -1025,7 +1025,11 @@ module Temporalio
1025
1025
  Api::WorkflowService::V1::DescribeActivityExecutionRequest.new(
1026
1026
  namespace: @client.namespace,
1027
1027
  activity_id: input.activity_id,
1028
- run_id: input.activity_run_id || ''
1028
+ run_id: input.activity_run_id || '',
1029
+ include_input: input.include_input,
1030
+ include_outcome: input.include_outcome,
1031
+ include_heartbeat_details: input.include_heartbeat_details,
1032
+ include_last_failure: input.include_last_failure
1029
1033
  ),
1030
1034
  rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
1031
1035
  )
@@ -1062,6 +1066,54 @@ module Temporalio
1062
1066
  nil
1063
1067
  end
1064
1068
 
1069
+ def pause_activity(input)
1070
+ @client.workflow_service.pause_activity_execution(
1071
+ Api::WorkflowService::V1::PauseActivityExecutionRequest.new(
1072
+ namespace: @client.namespace,
1073
+ activity_id: input.activity_id,
1074
+ run_id: input.activity_run_id || '',
1075
+ identity: @client.connection.identity,
1076
+ request_id: SecureRandom.uuid,
1077
+ reason: input.reason || ''
1078
+ ),
1079
+ rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
1080
+ )
1081
+ nil
1082
+ end
1083
+
1084
+ def unpause_activity(input)
1085
+ @client.workflow_service.unpause_activity_execution(
1086
+ Api::WorkflowService::V1::UnpauseActivityExecutionRequest.new(
1087
+ namespace: @client.namespace,
1088
+ activity_id: input.activity_id,
1089
+ run_id: input.activity_run_id || '',
1090
+ identity: @client.connection.identity,
1091
+ request_id: SecureRandom.uuid,
1092
+ reason: input.reason || '',
1093
+ jitter: ProtoUtils.seconds_to_duration(input.jitter)
1094
+ ),
1095
+ rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
1096
+ )
1097
+ nil
1098
+ end
1099
+
1100
+ def update_activity_options(input)
1101
+ resp = @client.workflow_service.update_activity_execution_options(
1102
+ Api::WorkflowService::V1::UpdateActivityExecutionOptionsRequest.new(
1103
+ namespace: @client.namespace,
1104
+ activity_id: input.activity_id,
1105
+ run_id: input.activity_run_id || '',
1106
+ identity: @client.connection.identity,
1107
+ request_id: SecureRandom.uuid,
1108
+ activity_options: input.activity_options,
1109
+ update_mask: input.update_mask,
1110
+ restore_original: input.restore_original
1111
+ ),
1112
+ rpc_options: Implementation.with_default_rpc_options(input.rpc_options)
1113
+ )
1114
+ Temporalio::Client::ActivityExecutionOptions._from_proto(resp.activity_options)
1115
+ end
1116
+
1065
1117
  def list_activities(input)
1066
1118
  Enumerator.new do |yielder|
1067
1119
  req = Api::WorkflowService::V1::ListActivityExecutionsRequest.new(
@@ -106,6 +106,9 @@ module Temporalio
106
106
  message_str = message.is_a?(String) ? message : message.inspect
107
107
  "#{message_str} #{scoped_values}"
108
108
  end
109
+
110
+ # @return [String] The log message.
111
+ alias to_s message
109
112
  end
110
113
  end
111
114
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Temporalio
4
- VERSION = '1.7.0'
4
+ VERSION = '1.8.0'
5
5
  end
@@ -39,8 +39,18 @@ module Temporalio
39
39
  return unless defn.cancel_raise
40
40
 
41
41
  fiber = ::Fiber.current
42
+ scheduler = ::Fiber.scheduler
43
+ scheduler = nil unless scheduler.respond_to?(:fiber_interrupt)
42
44
  context&.cancellation&.add_cancel_callback do
43
- fiber.raise(Error::CanceledError.new('Activity canceled'))
45
+ error = Error::CanceledError.new('Activity canceled')
46
+ # Directly raising from another fiber can strand a `Fiber#transfer`
47
+ # based scheduler's current fiber, so we defer to the scheduler to interrupt.
48
+ # If on the same fiber, we can just raise directly.
49
+ if scheduler.nil? || ::Fiber.current.equal?(fiber)
50
+ fiber.raise(error)
51
+ else
52
+ scheduler.fiber_interrupt(fiber, error)
53
+ end
44
54
  end
45
55
  end
46
56
  end