temporalio 0.4.0 → 0.5.0

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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/Cargo.lock +679 -437
  4. data/Cargo.toml +5 -5
  5. data/README.md +98 -34
  6. data/ext/Cargo.toml +3 -3
  7. data/lib/temporalio/activity/cancellation_details.rb +58 -0
  8. data/lib/temporalio/activity/context.rb +10 -1
  9. data/lib/temporalio/activity/definition.rb +41 -3
  10. data/lib/temporalio/activity/info.rb +25 -4
  11. data/lib/temporalio/activity.rb +2 -0
  12. data/lib/temporalio/api/activity/v1/message.rb +1 -1
  13. data/lib/temporalio/api/batch/v1/message.rb +4 -2
  14. data/lib/temporalio/api/cloud/account/v1/message.rb +1 -1
  15. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +11 -2
  16. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +2 -2
  17. data/lib/temporalio/api/cloud/identity/v1/message.rb +7 -2
  18. data/lib/temporalio/api/cloud/namespace/v1/message.rb +6 -2
  19. data/lib/temporalio/api/cloud/nexus/v1/message.rb +3 -2
  20. data/lib/temporalio/api/cloud/operation/v1/message.rb +1 -1
  21. data/lib/temporalio/api/cloud/region/v1/message.rb +1 -1
  22. data/lib/temporalio/api/cloud/resource/v1/message.rb +1 -1
  23. data/lib/temporalio/api/cloud/sink/v1/message.rb +1 -1
  24. data/lib/temporalio/api/cloud/usage/v1/message.rb +1 -1
  25. data/lib/temporalio/api/command/v1/message.rb +2 -2
  26. data/lib/temporalio/api/common/v1/grpc_status.rb +1 -1
  27. data/lib/temporalio/api/common/v1/message.rb +3 -2
  28. data/lib/temporalio/api/deployment/v1/message.rb +3 -2
  29. data/lib/temporalio/api/enums/v1/batch_operation.rb +1 -1
  30. data/lib/temporalio/api/enums/v1/command_type.rb +1 -1
  31. data/lib/temporalio/api/enums/v1/common.rb +5 -2
  32. data/lib/temporalio/api/enums/v1/deployment.rb +3 -2
  33. data/lib/temporalio/api/enums/v1/event_type.rb +2 -2
  34. data/lib/temporalio/api/enums/v1/failed_cause.rb +2 -2
  35. data/lib/temporalio/api/enums/v1/namespace.rb +1 -1
  36. data/lib/temporalio/api/enums/v1/nexus.rb +1 -1
  37. data/lib/temporalio/api/enums/v1/query.rb +1 -1
  38. data/lib/temporalio/api/enums/v1/reset.rb +1 -1
  39. data/lib/temporalio/api/enums/v1/schedule.rb +1 -1
  40. data/lib/temporalio/api/enums/v1/task_queue.rb +1 -1
  41. data/lib/temporalio/api/enums/v1/update.rb +1 -1
  42. data/lib/temporalio/api/enums/v1/workflow.rb +2 -2
  43. data/lib/temporalio/api/errordetails/v1/message.rb +1 -1
  44. data/lib/temporalio/api/export/v1/message.rb +1 -1
  45. data/lib/temporalio/api/failure/v1/message.rb +3 -2
  46. data/lib/temporalio/api/filter/v1/message.rb +1 -1
  47. data/lib/temporalio/api/history/v1/message.rb +4 -2
  48. data/lib/temporalio/api/namespace/v1/message.rb +1 -1
  49. data/lib/temporalio/api/nexus/v1/message.rb +2 -2
  50. data/lib/temporalio/api/operatorservice/v1/request_response.rb +1 -1
  51. data/lib/temporalio/api/operatorservice/v1/service.rb +1 -1
  52. data/lib/temporalio/api/payload_visitor.rb +87 -0
  53. data/lib/temporalio/api/protocol/v1/message.rb +1 -1
  54. data/lib/temporalio/api/query/v1/message.rb +1 -1
  55. data/lib/temporalio/api/replication/v1/message.rb +1 -1
  56. data/lib/temporalio/api/rules/v1/message.rb +27 -0
  57. data/lib/temporalio/api/schedule/v1/message.rb +2 -2
  58. data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +1 -1
  59. data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +1 -1
  60. data/lib/temporalio/api/sdk/v1/user_metadata.rb +1 -1
  61. data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +1 -1
  62. data/lib/temporalio/api/taskqueue/v1/message.rb +2 -2
  63. data/lib/temporalio/api/testservice/v1/request_response.rb +1 -1
  64. data/lib/temporalio/api/testservice/v1/service.rb +1 -1
  65. data/lib/temporalio/api/update/v1/message.rb +1 -1
  66. data/lib/temporalio/api/version/v1/message.rb +1 -1
  67. data/lib/temporalio/api/worker/v1/message.rb +30 -0
  68. data/lib/temporalio/api/workflow/v1/message.rb +14 -2
  69. data/lib/temporalio/api/workflowservice/v1/request_response.rb +19 -2
  70. data/lib/temporalio/api/workflowservice/v1/service.rb +2 -2
  71. data/lib/temporalio/client/async_activity_handle.rb +12 -4
  72. data/lib/temporalio/client/connection/cloud_service.rb +60 -0
  73. data/lib/temporalio/client/connection/workflow_service.rb +105 -0
  74. data/lib/temporalio/client/interceptor.rb +25 -7
  75. data/lib/temporalio/client/schedule.rb +10 -2
  76. data/lib/temporalio/client/with_start_workflow_operation.rb +9 -1
  77. data/lib/temporalio/client/workflow_handle.rb +50 -10
  78. data/lib/temporalio/client/workflow_update_handle.rb +9 -3
  79. data/lib/temporalio/client.rb +110 -6
  80. data/lib/temporalio/common_enums.rb +14 -0
  81. data/lib/temporalio/contrib/open_telemetry.rb +13 -9
  82. data/lib/temporalio/converters/data_converter.rb +18 -8
  83. data/lib/temporalio/converters/failure_converter.rb +6 -3
  84. data/lib/temporalio/converters/payload_converter/binary_null.rb +2 -2
  85. data/lib/temporalio/converters/payload_converter/binary_plain.rb +2 -2
  86. data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +2 -2
  87. data/lib/temporalio/converters/payload_converter/composite.rb +6 -4
  88. data/lib/temporalio/converters/payload_converter/encoding.rb +4 -2
  89. data/lib/temporalio/converters/payload_converter/json_plain.rb +2 -2
  90. data/lib/temporalio/converters/payload_converter/json_protobuf.rb +2 -2
  91. data/lib/temporalio/converters/payload_converter.rb +16 -6
  92. data/lib/temporalio/error/failure.rb +19 -1
  93. data/lib/temporalio/error.rb +1 -1
  94. data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +1 -1
  95. data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +3 -2
  96. data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +1 -1
  97. data/lib/temporalio/internal/bridge/api/common/common.rb +1 -1
  98. data/lib/temporalio/internal/bridge/api/core_interface.rb +1 -1
  99. data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +1 -1
  100. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +3 -2
  101. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +2 -2
  102. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +3 -2
  103. data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +1 -1
  104. data/lib/temporalio/internal/bridge/worker.rb +28 -4
  105. data/lib/temporalio/internal/bridge.rb +1 -1
  106. data/lib/temporalio/internal/client/implementation.rb +60 -52
  107. data/lib/temporalio/internal/proto_utils.rb +4 -4
  108. data/lib/temporalio/internal/worker/activity_worker.rb +93 -20
  109. data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +8 -6
  110. data/lib/temporalio/internal/worker/workflow_instance/context.rb +65 -24
  111. data/lib/temporalio/internal/worker/workflow_instance/details.rb +5 -2
  112. data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +2 -2
  113. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +64 -18
  114. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +28 -14
  115. data/lib/temporalio/internal/worker/workflow_instance.rb +58 -23
  116. data/lib/temporalio/internal/worker/workflow_worker.rb +16 -6
  117. data/lib/temporalio/priority.rb +59 -0
  118. data/lib/temporalio/testing/activity_environment.rb +17 -2
  119. data/lib/temporalio/testing/workflow_environment.rb +3 -3
  120. data/lib/temporalio/version.rb +1 -1
  121. data/lib/temporalio/versioning_override.rb +56 -0
  122. data/lib/temporalio/worker/deployment_options.rb +45 -0
  123. data/lib/temporalio/worker/illegal_workflow_call_validator.rb +64 -0
  124. data/lib/temporalio/worker/interceptor.rb +13 -1
  125. data/lib/temporalio/worker/poller_behavior.rb +61 -0
  126. data/lib/temporalio/worker/thread_pool.rb +1 -1
  127. data/lib/temporalio/worker/workflow_executor/thread_pool.rb +2 -1
  128. data/lib/temporalio/worker/workflow_replayer.rb +12 -13
  129. data/lib/temporalio/worker.rb +63 -27
  130. data/lib/temporalio/worker_deployment_version.rb +67 -0
  131. data/lib/temporalio/workflow/child_workflow_handle.rb +10 -2
  132. data/lib/temporalio/workflow/definition.rb +183 -33
  133. data/lib/temporalio/workflow/external_workflow_handle.rb +3 -1
  134. data/lib/temporalio/workflow/info.rb +4 -1
  135. data/lib/temporalio/workflow.rb +61 -9
  136. data/lib/temporalio.rb +1 -0
  137. data/temporalio.gemspec +1 -0
  138. metadata +12 -3
data/Cargo.toml CHANGED
@@ -13,13 +13,13 @@ license-file = "LICENSE"
13
13
 
14
14
  [workspace.dependencies]
15
15
  derive_builder = "0.20"
16
- derive_more = { version = "1.0", features = ["constructor", "display", "from", "into", "debug"] }
16
+ derive_more = { version = "2.0", features = ["constructor", "display", "from", "into", "debug", "try_into"] }
17
17
  thiserror = "2"
18
- tonic = "0.12"
19
- tonic-build = "0.12"
20
- opentelemetry = { version = "0.26", features = ["metrics"] }
18
+ tonic = "0.13"
19
+ tonic-build = "0.13"
20
+ opentelemetry = { version = "0.30", features = ["metrics"] }
21
21
  prost = "0.13"
22
22
  prost-types = "0.13"
23
23
 
24
24
  [workspace.lints.rust]
25
- unreachable_pub = "warn"
25
+ unreachable_pub = "warn"
data/README.md CHANGED
@@ -42,7 +42,8 @@ opinions. Please communicate with us on [Slack](https://t.mp/slack) in the `#rub
42
42
  - [Cloud Client Using mTLS](#cloud-client-using-mtls)
43
43
  - [Cloud Client Using API Key](#cloud-client-using-api-key)
44
44
  - [Data Conversion](#data-conversion)
45
- - [ActiveRecord and ActiveModel](#activerecord-and-activemodel)
45
+ - [ActiveModel](#activemodel)
46
+ - [Converter Hints](#converter-hints)
46
47
  - [Workers](#workers)
47
48
  - [Workflows](#workflows)
48
49
  - [Workflow Definition](#workflow-definition)
@@ -71,6 +72,10 @@ opinions. Please communicate with us on [Slack](https://t.mp/slack) in the `#rub
71
72
  - [Metrics](#metrics)
72
73
  - [OpenTelemetry Tracing](#opentelemetry-tracing)
73
74
  - [OpenTelemetry Tracing in Workflows](#opentelemetry-tracing-in-workflows)
75
+ - [Rails](#rails)
76
+ - [ActiveRecord](#activerecord)
77
+ - [Lazy/Eager Loading](#lazyeager-loading)
78
+ - [Forking](#forking)
74
79
  - [Ractors](#ractors)
75
80
  - [Platform Support](#platform-support)
76
81
  - [Development](#development)
@@ -295,57 +300,62 @@ will be tried in order until one accepts (default falls through to the JSON one)
295
300
  `encoding` metadata value which is used to know which converter to use on deserialize. Custom encoding converters can be
296
301
  created, or even the entire payload converter can be replaced with a different implementation.
297
302
 
298
- ##### ActiveRecord and ActiveModel
303
+ **NOTE:** For ActiveRecord, or other general/ORM models that are used for a different purpose, it is not recommended to
304
+ try to reuse them as Temporal models. Eventually model purposes diverge and models for a Temporal workflows/activities
305
+ should be specific to their use for clarity and compatibility reasons. Also many Ruby ORMs do many lazy things and
306
+ therefore provide unclear serialization semantics. Instead, consider having models specific for workflows/activities and
307
+ translate to/from existing models as needed. See the next section on how to do this with ActiveModel objects.
299
308
 
300
- By default, `ActiveRecord` and `ActiveModel` objects do not natively support the `JSON` module. A mixin can be created
301
- to add this support for `ActiveRecord`, for example:
309
+ ##### ActiveModel
310
+
311
+ By default, ActiveModel objects do not natively support the `JSON` module. A mixin can be created to add this support
312
+ for ActiveRecord, for example:
302
313
 
303
314
  ```ruby
304
- module ActiveRecordJSONSupport
315
+ module ActiveModelJSONSupport
305
316
  extend ActiveSupport::Concern
306
317
  include ActiveModel::Serializers::JSON
307
318
 
308
319
  included do
320
+ def as_json(*)
321
+ super.merge(::JSON.create_id => self.class.name)
322
+ end
323
+
309
324
  def to_json(*args)
310
- hash = as_json
311
- hash[::JSON.create_id] = self.class.name
312
- hash.to_json(*args)
325
+ as_json.to_json(*args)
313
326
  end
314
327
 
315
328
  def self.json_create(object)
329
+ object = object.dup
316
330
  object.delete(::JSON.create_id)
317
- ret = new
318
- ret.attributes = object
319
- ret
331
+ new(**object.symbolize_keys)
320
332
  end
321
333
  end
322
334
  end
323
335
  ```
324
336
 
325
- Similarly, a mixin for `ActiveModel` that adds `attributes` accessors can leverage this same mixin, for example:
337
+ Now if `include ActiveModelJSONSupport` is present on any ActiveModel class, on serialization `to_json` will be used
338
+ which will use `as_json` which calls the super `as_json` but also includes the fully qualified class name as the JSON
339
+ `create_id` key. On deserialization, Ruby JSON then uses this key to know what class to call `json_create` on.
326
340
 
327
- ```ruby
328
- module ActiveModelJSONSupport
329
- extend ActiveSupport::Concern
330
- include ActiveRecordJSONSupport
341
+ ##### Converter Hints
331
342
 
332
- included do
333
- def attributes=(hash)
334
- hash.each do |key, value|
335
- send("#{key}=", value)
336
- end
337
- end
343
+ In most places where objects are converted to payloads or vice versa, a "hint" can be provided to tell the converter
344
+ something else about the object/payload to assist conversion. The default converters ignore these hints, but custom
345
+ converters can be written to take advantage of them. For example, hints may be used to provide a custom converter the
346
+ Ruby type to deserialize a payload into.
338
347
 
339
- def attributes
340
- instance_values
341
- end
342
- end
343
- end
344
- ```
348
+ These hints manifest themselves various ways throughout the API. The most obvious way is when making definitions. An
349
+ activity can define `activity_arg_hint` (which accepts multiple) and/or `activity_result_hint` for activity-level hints.
350
+ Similarly, a workflow can define `workflow_arg_hint` and/or `workflow_result_hint` for workflow-level hints.
351
+ `workflow_signal`, `workflow_query`, and `workflow_update` all similarly accept `arg_hints` and `result_hint` (except
352
+ signal of course). These definition-level hints are passed to converters both from the caller side and the
353
+ implementation side.
345
354
 
346
- Now `include ActiveRecordJSONSupport` or `include ActiveModelJSONSupport` will make the models work with Ruby `JSON`
347
- module and therefore Temporal. Of course any other approach to make the models work with the `JSON` module will work as
348
- well.
355
+ There are some advanced payload uses in the SDK that do not currently have a way to set hints. These include
356
+ workflow/schedule memo, workflow get/upsert memo, and application error details. In some cases, users can use
357
+ `Temporalio::Converters::RawValue` and then manually convert with hints. For others, hints can be added as needed,
358
+ please open an issue or otherwise contact Temporal.
349
359
 
350
360
  ### Workers
351
361
 
@@ -418,7 +428,7 @@ class GreetingWorkflow < Temporalio::Workflow::Definition
418
428
  # on wait_condition calls, so Cancellation object doesn't need to be passed
419
429
  # explicitly.
420
430
  Temporalio::Workflow.wait_condition { @greeting_params_update || @complete }
421
-
431
+
422
432
  # If there was an update, exchange and rerun. If it's _only_ a complete, finish
423
433
  # workflow with the greeting.
424
434
  if @greeting_params_update
@@ -490,7 +500,8 @@ definition/behavior of the method:
490
500
  side effects, meaning they should never mutate state or try to wait on anything.
491
501
 
492
502
  Workflows can be inherited, but subclass workflow-level decorators override superclass ones, and the same method can't
493
- be decorated with different handler types/names in the hierarchy.
503
+ be decorated with different handler types/names in the hierarchy. Workflow handlers (execute or any marked method)
504
+ cannot accept keyword arguments.
494
505
 
495
506
  #### Running Workflows
496
507
 
@@ -955,6 +966,7 @@ Some notes about activity definition:
955
966
  * `workflow_raw_args` can be used to have activity arguments delivered to `execute` as
956
967
  `Temporalio::Converters::RawValue`s. These are wrappers for the raw payloads that have not been converted to types
957
968
  (but they have been decoded by the codec if present). They can be converted with `payload_converter` on the context.
969
+ * Activities cannot accept keyword arguments.
958
970
 
959
971
  #### Activity Context
960
972
 
@@ -1154,6 +1166,53 @@ workflow and time to run the activity attempt respectively), but the other spans
1154
1166
  are created in workflows and closed immediately since long-lived spans cannot work for durable software that may resume
1155
1167
  on other machines.
1156
1168
 
1169
+ ### Rails
1170
+
1171
+ Temporal Ruby SDK is a generic Ruby library that can work in any Ruby environment. However, there are some common
1172
+ conventions for Rails users to be aware of.
1173
+
1174
+ See the [rails_app](https://github.com/temporalio/samples-ruby/tree/main/rails_app) sample for an example of using
1175
+ Temporal from Rails.
1176
+
1177
+ #### ActiveRecord
1178
+
1179
+ For ActiveRecord, or other general/ORM models that are used for a different purpose, it is not recommended to
1180
+ try to reuse them as Temporal models. Eventually model purposes diverge and models for a Temporal workflows/activities
1181
+ should be specific to their use for clarity and compatibility reasons. Also many Ruby ORMs do many lazy things and
1182
+ therefore provide unclear serialization semantics. Instead, consider having models specific for workflows/activities and
1183
+ translate to/from existing models as needed. See the [ActiveModel](#activemodel) section on how to do this with
1184
+ ActiveModel objects.
1185
+
1186
+ #### Lazy/Eager Loading
1187
+
1188
+ By default, Rails
1189
+ [eagerly loads](https://guides.rubyonrails.org/v7.2/autoloading_and_reloading_constants.html#eager-loading) all
1190
+ application code on application start in production, but lazily loads it in non-production environments. Temporal
1191
+ workflows by default disallow use of IO during the workflow run. With lazy loading enabled in dev/test environments,
1192
+ when an activity class is referenced in a workflow before it has been explicitly `require`d, it can give an error like:
1193
+
1194
+ > Cannot access File path from inside a workflow. If this is known to be safe, the code can be run in a
1195
+ > Temporalio::Workflow::Unsafe.illegal_call_tracing_disabled block.
1196
+
1197
+ This comes from `bootsnap` via `zeitwork` because it is lazily loading a class/module at workflow runtime. It is not
1198
+ good to lazily load code durnig a workflow run because it can be side effecting. Workflows and the classes they
1199
+ reference should not be eagerly loaded.
1200
+
1201
+ To resolve this, either always eagerly load (e.g. `config.eager_load = true`) or explicitly `require` what is used by a
1202
+ workflow at the top of the file.
1203
+
1204
+ Note, this only affects non-production environments.
1205
+
1206
+ ### Forking
1207
+
1208
+ Objects created with the Temporal Ruby SDK cannot be used across forks. This includes runtimes, clients, and workers. By
1209
+ default, using `Client.connect` uses `Runtime.default` which is lazily created. If it was already created on the parent,
1210
+ an exception will occur when trying to reuse it to create clients or workers in a forked child. Similarly any RPC
1211
+ invocation or worker execution inside of a forked child separate from where the runtime or client or worker were created
1212
+ will raise an exception.
1213
+
1214
+ If forking must be used, make sure Temporal objects are only created _inside_ the fork.
1215
+
1157
1216
  ### Ractors
1158
1217
 
1159
1218
  It was an original goal to have workflows actually be Ractors for deterministic state isolation and have the library
@@ -1203,9 +1262,11 @@ Prerequisites:
1203
1262
 
1204
1263
  First, install dependencies:
1205
1264
 
1265
+ # Optional: Change bundler install path to be local
1266
+ bundle config --local path $(pwd)/.bundle
1206
1267
  bundle install
1207
1268
 
1208
- To build shared library for development use:
1269
+ To build shared library for development use (ensure you have cloned submodules) :
1209
1270
 
1210
1271
  bundle exec rake compile
1211
1272
 
@@ -1237,6 +1298,9 @@ the gem at `lib/temporalio/internal/bridge/3.2/temporalio_bridge.so` and
1237
1298
 
1238
1299
  ### Testing
1239
1300
 
1301
+ Note you can set `TEMPORAL_TEST_CLIENT_TARGET_HOST` and `TEMPORAL_TEST_CLIENT_TARGET_NAMESPACE`
1302
+ (optional, defaults to 'default') environment variables to use an existing server.
1303
+
1240
1304
  This project uses `minitest`. To test:
1241
1305
 
1242
1306
  bundle exec rake test
data/ext/Cargo.toml CHANGED
@@ -1,7 +1,7 @@
1
1
  [package]
2
2
  name = "temporalio_bridge"
3
3
  version = "0.1.0"
4
- edition = "2021"
4
+ edition = "2024"
5
5
  authors = ["Chad Retz <chad@temporal.io>"]
6
6
  license = "MIT"
7
7
  publish = false
@@ -19,9 +19,9 @@ temporal-client = { version = "0.1.0", path = "./sdk-core/client" }
19
19
  temporal-sdk-core = { version = "0.1.0", path = "./sdk-core/core", features = ["ephemeral-server"] }
20
20
  temporal-sdk-core-api = { version = "0.1.0", path = "./sdk-core/core-api" }
21
21
  temporal-sdk-core-protos = { version = "0.1.0", path = "./sdk-core/sdk-core-protos" }
22
- tokio = "1.26"
22
+ tokio = "1.37"
23
23
  tokio-stream = "0.1"
24
24
  tokio-util = "0.7"
25
- tonic = "0.12"
25
+ tonic = "0.13"
26
26
  tracing = "0.1"
27
27
  url = "2.2"
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/error'
4
+
5
+ module Temporalio
6
+ module Activity
7
+ # Details that are set when an activity is cancelled. This is only valid at the time the cancel was received, the
8
+ # state may change on the server after it is received.
9
+ class CancellationDetails
10
+ def initialize(
11
+ gone_from_server: false,
12
+ cancel_requested: true,
13
+ timed_out: false,
14
+ worker_shutdown: false,
15
+ paused: false,
16
+ reset: false
17
+ )
18
+ @gone_from_server = gone_from_server
19
+ @cancel_requested = cancel_requested
20
+ @timed_out = timed_out
21
+ @worker_shutdown = worker_shutdown
22
+ @paused = paused
23
+ @reset = reset
24
+ end
25
+
26
+ # @return [Boolean] Whether the activity no longer exists on the server (may already be completed or its workflow
27
+ # may be completed).
28
+ def gone_from_server?
29
+ @gone_from_server
30
+ end
31
+
32
+ # @return [Boolean] Whether the activity was explicitly cancelled.
33
+ def cancel_requested?
34
+ @cancel_requested
35
+ end
36
+
37
+ # @return [Boolean] Whether the activity timeout caused activity to be marked cancelled.
38
+ def timed_out?
39
+ @timed_out
40
+ end
41
+
42
+ # @return [Boolean] Whether the worker the activity is running on is shutting down.
43
+ def worker_shutdown?
44
+ @worker_shutdown
45
+ end
46
+
47
+ # @return [Boolean] Whether the activity was explicitly paused.
48
+ def paused?
49
+ @paused
50
+ end
51
+
52
+ # @return [Boolean] Whether the activity was explicitly reset.
53
+ def reset?
54
+ @reset
55
+ end
56
+ end
57
+ end
58
+ end
@@ -61,7 +61,8 @@ module Temporalio
61
61
  # Users do not have to be concerned with burdening the server by calling this too frequently.
62
62
  #
63
63
  # @param details [Array<Object>] Details to record with the heartbeat.
64
- def heartbeat(*details)
64
+ # @param detail_hints [Array<Object>, nil] Hints to pass to converter.
65
+ def heartbeat(*details, detail_hints: nil)
65
66
  raise NotImplementedError
66
67
  end
67
68
 
@@ -70,6 +71,14 @@ module Temporalio
70
71
  raise NotImplementedError
71
72
  end
72
73
 
74
+ # @return [CancellationDetails, nil] Cancellation details if canceled. These are set just before cancellation is
75
+ # actually canceled. These details only represent when the cancel was first performed. Once set, this object is
76
+ # never mutated. Therefore, the situation on the server may have changed (e.g. unpause), but this still
77
+ # represents the values when cancellation first occurred for this attempt.
78
+ def cancellation_details
79
+ raise NotImplementedError
80
+ end
81
+
73
82
  # @return [Cancellation] Cancellation that is canceled when the worker is shutting down. On worker shutdown, this
74
83
  # is canceled, then the `graceful_shutdown_period` is waited (default 0s), then the activity is canceled.
75
84
  def worker_shutdown_cancellation
@@ -78,6 +78,21 @@ module Temporalio
78
78
 
79
79
  @activity_raw_args = value
80
80
  end
81
+
82
+ # Add activity hints to be passed to converter for activity args.
83
+ #
84
+ # @param hints [Array<Object>] Hints to add.
85
+ def activity_arg_hint(*hints)
86
+ @activity_arg_hints ||= []
87
+ @activity_arg_hints.concat(hints)
88
+ end
89
+
90
+ # Set activity result hint to be passed to converter for activity result.
91
+ #
92
+ # @param hint [Object] Hint to set.
93
+ def activity_result_hint(hint)
94
+ @activity_result_hint = hint
95
+ end
81
96
  end
82
97
 
83
98
  # @!visibility private
@@ -85,13 +100,20 @@ module Temporalio
85
100
  activity_name = @activity_name
86
101
  raise 'Cannot have activity name specified for dynamic activity' if activity_name && @activity_dynamic
87
102
 
103
+ # Disallow kwargs in execute parameters
104
+ if instance_method(:execute).parameters.any? { |t, _| t == :key || t == :keyreq }
105
+ raise 'Activity execute cannot have keyword arguments'
106
+ end
107
+
88
108
  # Default to unqualified class name if not dynamic
89
109
  activity_name ||= name.to_s.split('::').last unless @activity_dynamic
90
110
  {
91
111
  activity_name:,
92
112
  activity_executor: @activity_executor || :default,
93
113
  activity_cancel_raise: @activity_cancel_raise.nil? || @activity_cancel_raise,
94
- activity_raw_args: @activity_raw_args.nil? ? false : @activity_raw_args
114
+ activity_raw_args: @activity_raw_args.nil? ? false : @activity_raw_args,
115
+ activity_arg_hints: @activity_arg_hints,
116
+ activity_result_hint: @activity_result_hint
95
117
  }
96
118
  end
97
119
 
@@ -122,6 +144,12 @@ module Temporalio
122
144
  # @return [Boolean] Whether to use {Converters::RawValue}s as arguments.
123
145
  attr_reader :raw_args
124
146
 
147
+ # @return [Array<Object>, nil] Argument hints.
148
+ attr_reader :arg_hints
149
+
150
+ # @return [Object, nil] Result hint
151
+ attr_reader :result_hint
152
+
125
153
  # Obtain definition info representing the given activity, which can be a class, instance, or definition info.
126
154
  #
127
155
  # @param activity [Definition, Class<Definition>, Info] Activity to get info for.
@@ -142,7 +170,9 @@ module Temporalio
142
170
  instance: proc { activity.new },
143
171
  executor: details[:activity_executor],
144
172
  cancel_raise: details[:activity_cancel_raise],
145
- raw_args: details[:activity_raw_args]
173
+ raw_args: details[:activity_raw_args],
174
+ arg_hints: details[:activity_arg_hints],
175
+ result_hint: details[:activity_result_hint]
146
176
  ) { |*args| Context.current.instance&.execute(*args) }
147
177
  when Definition
148
178
  details = activity.class._activity_definition_details
@@ -151,7 +181,9 @@ module Temporalio
151
181
  instance: activity,
152
182
  executor: details[:activity_executor],
153
183
  cancel_raise: details[:activity_cancel_raise],
154
- raw_args: details[:activity_raw_args]
184
+ raw_args: details[:activity_raw_args],
185
+ arg_hints: details[:activity_arg_hints],
186
+ result_hint: details[:activity_result_hint]
155
187
  ) { |*args| Context.current.instance&.execute(*args) }
156
188
  when Info
157
189
  activity
@@ -167,6 +199,8 @@ module Temporalio
167
199
  # @param executor [Symbol] Name of the executor.
168
200
  # @param cancel_raise [Boolean] Whether to raise in thread/fiber on cancellation.
169
201
  # @param raw_args [Boolean] Whether to use {Converters::RawValue}s as arguments.
202
+ # @param arg_hints [Array<Object>, nil] Argument hints.
203
+ # @param result_hint [Object, nil] Result hint.
170
204
  # @yield Use this block as the activity.
171
205
  def initialize(
172
206
  name:,
@@ -174,6 +208,8 @@ module Temporalio
174
208
  executor: :default,
175
209
  cancel_raise: true,
176
210
  raw_args: false,
211
+ arg_hints: nil,
212
+ result_hint: nil,
177
213
  &block
178
214
  )
179
215
  @name = name
@@ -184,6 +220,8 @@ module Temporalio
184
220
  @executor = executor
185
221
  @cancel_raise = cancel_raise
186
222
  @raw_args = raw_args
223
+ @arg_hints = arg_hints
224
+ @result_hint = result_hint
187
225
  Internal::ProtoUtils.assert_non_reserved_name(name)
188
226
  end
189
227
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'temporalio/activity/context'
4
+ require 'temporalio/internal/proto_utils'
5
+
3
6
  module Temporalio
4
7
  module Activity
5
8
  Info = Data.define(
@@ -7,9 +10,10 @@ module Temporalio
7
10
  :activity_type,
8
11
  :attempt,
9
12
  :current_attempt_scheduled_time,
10
- :heartbeat_details,
11
13
  :heartbeat_timeout,
12
14
  :local?,
15
+ :priority,
16
+ :raw_heartbeat_details,
13
17
  :schedule_to_close_timeout,
14
18
  :scheduled_time,
15
19
  :start_to_close_timeout,
@@ -32,12 +36,15 @@ module Temporalio
32
36
  # @return [Integer] Attempt the activity is on.
33
37
  # @!attribute current_attempt_scheduled_time
34
38
  # @return [Time] When the current attempt was scheduled.
35
- # @!attribute heartbeat_details
36
- # @return [Array<Object>] Details from the last heartbeat of the last attempt.
37
39
  # @!attribute heartbeat_timeout
38
40
  # @return [Float, nil] Heartbeat timeout set by the caller.
39
41
  # @!attribute local?
40
42
  # @return [Boolean] Whether the activity is a local activity or not.
43
+ # @!attribute priority
44
+ # @return [Priority] The priority of this activity.
45
+ # @!attribute raw_heartbeat_details
46
+ # @return [Array<Converter::RawValue>] Raw details from the last heartbeat of the last attempt. Can use
47
+ # {heartbeat_details} to get lazily-converted values.
41
48
  # @!attribute schedule_to_close_timeout
42
49
  # @return [Float, nil] Schedule to close timeout set by the caller.
43
50
  # @!attribute scheduled_time
@@ -62,6 +69,20 @@ module Temporalio
62
69
  #
63
70
  # @note WARNING: This class may have required parameters added to its constructor. Users should not instantiate this
64
71
  # class or it may break in incompatible ways.
65
- class Info; end # rubocop:disable Lint/EmptyClass
72
+ class Info
73
+ # Convert raw heartbeat details into Ruby types.
74
+ #
75
+ # Note, this live-converts every invocation.
76
+ #
77
+ # @param hints [Array<Object>, nil] Hints, if any, to assist conversion.
78
+ # @return [Array<Object>] Converted details.
79
+ def heartbeat_details(hints: nil)
80
+ Internal::ProtoUtils.convert_from_payload_array(
81
+ Context.current.payload_converter,
82
+ raw_heartbeat_details.map(&:payload),
83
+ hints:
84
+ )
85
+ end
86
+ end
66
87
  end
67
88
  end
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'temporalio/activity/cancellation_details'
3
4
  require 'temporalio/activity/complete_async_error'
4
5
  require 'temporalio/activity/context'
5
6
  require 'temporalio/activity/definition'
6
7
  require 'temporalio/activity/info'
8
+ require 'temporalio/priority'
7
9
 
8
10
  module Temporalio
9
11
  # All activity related classes.
@@ -11,7 +11,7 @@ require 'google/protobuf/duration_pb'
11
11
 
12
12
  descriptor_data = "\n&temporal/api/activity/v1/message.proto\x12\x18temporal.api.activity.v1\x1a$temporal/api/common/v1/message.proto\x1a\'temporal/api/taskqueue/v1/message.proto\x1a\x1egoogle/protobuf/duration.proto\"\xf3\x02\n\x0f\x41\x63tivityOptions\x12\x38\n\ntask_queue\x18\x01 \x01(\x0b\x32$.temporal.api.taskqueue.v1.TaskQueue\x12<\n\x19schedule_to_close_timeout\x18\x02 \x01(\x0b\x32\x19.google.protobuf.Duration\x12<\n\x19schedule_to_start_timeout\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x39\n\x16start_to_close_timeout\x18\x04 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x34\n\x11heartbeat_timeout\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x39\n\x0cretry_policy\x18\x06 \x01(\x0b\x32#.temporal.api.common.v1.RetryPolicyB\x93\x01\n\x1bio.temporal.api.activity.v1B\x0cMessageProtoP\x01Z\'go.temporal.io/api/activity/v1;activity\xaa\x02\x1aTemporalio.Api.Activity.V1\xea\x02\x1dTemporalio::Api::Activity::V1b\x06proto3"
13
13
 
14
- pool = Google::Protobuf::DescriptorPool.generated_pool
14
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
15
15
  pool.add_serialized_file(descriptor_data)
16
16
 
17
17
  module Temporalio
@@ -10,12 +10,13 @@ require 'google/protobuf/timestamp_pb'
10
10
  require 'temporalio/api/common/v1/message'
11
11
  require 'temporalio/api/enums/v1/batch_operation'
12
12
  require 'temporalio/api/enums/v1/reset'
13
+ require 'temporalio/api/rules/v1/message'
13
14
  require 'temporalio/api/workflow/v1/message'
14
15
 
15
16
 
16
- descriptor_data = "\n#temporal/api/batch/v1/message.proto\x12\x15temporal.api.batch.v1\x1a\x1egoogle/protobuf/duration.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$temporal/api/common/v1/message.proto\x1a+temporal/api/enums/v1/batch_operation.proto\x1a!temporal/api/enums/v1/reset.proto\x1a&temporal/api/workflow/v1/message.proto\"\xbf\x01\n\x12\x42\x61tchOperationInfo\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12\x39\n\x05state\x18\x02 \x01(\x0e\x32*.temporal.api.enums.v1.BatchOperationState\x12.\n\nstart_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nclose_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"`\n\x19\x42\x61tchOperationTermination\x12\x31\n\x07\x64\x65tails\x18\x01 \x01(\x0b\x32 .temporal.api.common.v1.Payloads\x12\x10\n\x08identity\x18\x02 \x01(\t\"\x99\x01\n\x14\x42\x61tchOperationSignal\x12\x0e\n\x06signal\x18\x01 \x01(\t\x12/\n\x05input\x18\x02 \x01(\x0b\x32 .temporal.api.common.v1.Payloads\x12.\n\x06header\x18\x03 \x01(\x0b\x32\x1e.temporal.api.common.v1.Header\x12\x10\n\x08identity\x18\x04 \x01(\t\".\n\x1a\x42\x61tchOperationCancellation\x12\x10\n\x08identity\x18\x01 \x01(\t\"*\n\x16\x42\x61tchOperationDeletion\x12\x10\n\x08identity\x18\x01 \x01(\t\"\xd9\x01\n\x13\x42\x61tchOperationReset\x12\x10\n\x08identity\x18\x03 \x01(\t\x12\x35\n\x07options\x18\x04 \x01(\x0b\x32$.temporal.api.common.v1.ResetOptions\x12\x34\n\nreset_type\x18\x01 \x01(\x0e\x32 .temporal.api.enums.v1.ResetType\x12\x43\n\x12reset_reapply_type\x18\x02 \x01(\x0e\x32\'.temporal.api.enums.v1.ResetReapplyType\"\xc9\x01\n,BatchOperationUpdateWorkflowExecutionOptions\x12\x10\n\x08identity\x18\x01 \x01(\t\x12V\n\x1aworkflow_execution_options\x18\x02 \x01(\x0b\x32\x32.temporal.api.workflow.v1.WorkflowExecutionOptions\x12/\n\x0bupdate_mask\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.FieldMask\"\xc0\x01\n\x1f\x42\x61tchOperationUnpauseActivities\x12\x10\n\x08identity\x18\x01 \x01(\t\x12\x0e\n\x04type\x18\x02 \x01(\tH\x00\x12\x13\n\tmatch_all\x18\x03 \x01(\x08H\x00\x12\x16\n\x0ereset_attempts\x18\x04 \x01(\x08\x12\x17\n\x0freset_heartbeat\x18\x05 \x01(\x08\x12)\n\x06jitter\x18\x06 \x01(\x0b\x32\x19.google.protobuf.DurationB\n\n\x08\x61\x63tivityB\x84\x01\n\x18io.temporal.api.batch.v1B\x0cMessageProtoP\x01Z!go.temporal.io/api/batch/v1;batch\xaa\x02\x17Temporalio.Api.Batch.V1\xea\x02\x1aTemporalio::Api::Batch::V1b\x06proto3"
17
+ descriptor_data = "\n#temporal/api/batch/v1/message.proto\x12\x15temporal.api.batch.v1\x1a\x1egoogle/protobuf/duration.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$temporal/api/common/v1/message.proto\x1a+temporal/api/enums/v1/batch_operation.proto\x1a!temporal/api/enums/v1/reset.proto\x1a#temporal/api/rules/v1/message.proto\x1a&temporal/api/workflow/v1/message.proto\"\xbf\x01\n\x12\x42\x61tchOperationInfo\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12\x39\n\x05state\x18\x02 \x01(\x0e\x32*.temporal.api.enums.v1.BatchOperationState\x12.\n\nstart_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nclose_time\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"`\n\x19\x42\x61tchOperationTermination\x12\x31\n\x07\x64\x65tails\x18\x01 \x01(\x0b\x32 .temporal.api.common.v1.Payloads\x12\x10\n\x08identity\x18\x02 \x01(\t\"\x99\x01\n\x14\x42\x61tchOperationSignal\x12\x0e\n\x06signal\x18\x01 \x01(\t\x12/\n\x05input\x18\x02 \x01(\x0b\x32 .temporal.api.common.v1.Payloads\x12.\n\x06header\x18\x03 \x01(\x0b\x32\x1e.temporal.api.common.v1.Header\x12\x10\n\x08identity\x18\x04 \x01(\t\".\n\x1a\x42\x61tchOperationCancellation\x12\x10\n\x08identity\x18\x01 \x01(\t\"*\n\x16\x42\x61tchOperationDeletion\x12\x10\n\x08identity\x18\x01 \x01(\t\"\xae\x02\n\x13\x42\x61tchOperationReset\x12\x10\n\x08identity\x18\x03 \x01(\t\x12\x35\n\x07options\x18\x04 \x01(\x0b\x32$.temporal.api.common.v1.ResetOptions\x12\x38\n\nreset_type\x18\x01 \x01(\x0e\x32 .temporal.api.enums.v1.ResetTypeB\x02\x18\x01\x12G\n\x12reset_reapply_type\x18\x02 \x01(\x0e\x32\'.temporal.api.enums.v1.ResetReapplyTypeB\x02\x18\x01\x12K\n\x15post_reset_operations\x18\x05 \x03(\x0b\x32,.temporal.api.workflow.v1.PostResetOperation\"\xc9\x01\n,BatchOperationUpdateWorkflowExecutionOptions\x12\x10\n\x08identity\x18\x01 \x01(\t\x12V\n\x1aworkflow_execution_options\x18\x02 \x01(\x0b\x32\x32.temporal.api.workflow.v1.WorkflowExecutionOptions\x12/\n\x0bupdate_mask\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.FieldMask\"\xc0\x01\n\x1f\x42\x61tchOperationUnpauseActivities\x12\x10\n\x08identity\x18\x01 \x01(\t\x12\x0e\n\x04type\x18\x02 \x01(\tH\x00\x12\x13\n\tmatch_all\x18\x03 \x01(\x08H\x00\x12\x16\n\x0ereset_attempts\x18\x04 \x01(\x08\x12\x17\n\x0freset_heartbeat\x18\x05 \x01(\x08\x12)\n\x06jitter\x18\x06 \x01(\x0b\x32\x19.google.protobuf.DurationB\n\n\x08\x61\x63tivity\"\x84\x01\n!BatchOperationTriggerWorkflowRule\x12\x10\n\x08identity\x18\x01 \x01(\t\x12\x0c\n\x02id\x18\x02 \x01(\tH\x00\x12\x37\n\x04spec\x18\x03 \x01(\x0b\x32\'.temporal.api.rules.v1.WorkflowRuleSpecH\x00\x42\x06\n\x04ruleB\x84\x01\n\x18io.temporal.api.batch.v1B\x0cMessageProtoP\x01Z!go.temporal.io/api/batch/v1;batch\xaa\x02\x17Temporalio.Api.Batch.V1\xea\x02\x1aTemporalio::Api::Batch::V1b\x06proto3"
17
18
 
18
- pool = Google::Protobuf::DescriptorPool.generated_pool
19
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
19
20
  pool.add_serialized_file(descriptor_data)
20
21
 
21
22
  module Temporalio
@@ -30,6 +31,7 @@ module Temporalio
30
31
  BatchOperationReset = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("temporal.api.batch.v1.BatchOperationReset").msgclass
31
32
  BatchOperationUpdateWorkflowExecutionOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("temporal.api.batch.v1.BatchOperationUpdateWorkflowExecutionOptions").msgclass
32
33
  BatchOperationUnpauseActivities = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("temporal.api.batch.v1.BatchOperationUnpauseActivities").msgclass
34
+ BatchOperationTriggerWorkflowRule = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("temporal.api.batch.v1.BatchOperationTriggerWorkflowRule").msgclass
33
35
  end
34
36
  end
35
37
  end
@@ -9,7 +9,7 @@ require 'temporalio/api/cloud/resource/v1/message'
9
9
 
10
10
  descriptor_data = "\n+temporal/api/cloud/account/v1/message.proto\x12\x1dtemporal.api.cloud.account.v1\x1a,temporal/api/cloud/resource/v1/message.proto\")\n\x0bMetricsSpec\x12\x1a\n\x12\x61\x63\x63\x65pted_client_ca\x18\x02 \x01(\x0c\"J\n\x0b\x41\x63\x63ountSpec\x12;\n\x07metrics\x18\x01 \x01(\x0b\x32*.temporal.api.cloud.account.v1.MetricsSpec\"\x16\n\x07Metrics\x12\x0b\n\x03uri\x18\x01 \x01(\t\"\xfc\x01\n\x07\x41\x63\x63ount\x12\n\n\x02id\x18\x01 \x01(\t\x12\x38\n\x04spec\x18\x02 \x01(\x0b\x32*.temporal.api.cloud.account.v1.AccountSpec\x12\x18\n\x10resource_version\x18\x03 \x01(\t\x12<\n\x05state\x18\x04 \x01(\x0e\x32-.temporal.api.cloud.resource.v1.ResourceState\x12\x1a\n\x12\x61sync_operation_id\x18\x05 \x01(\t\x12\x37\n\x07metrics\x18\x06 \x01(\x0b\x32&.temporal.api.cloud.account.v1.MetricsB\xa7\x01\n io.temporal.api.cloud.account.v1B\x0cMessageProtoP\x01Z+go.temporal.io/api/cloud/account/v1;account\xaa\x02\x1fTemporalio.Api.Cloud.Account.V1\xea\x02#Temporalio::Api::Cloud::Account::V1b\x06proto3"
11
11
 
12
- pool = Google::Protobuf::DescriptorPool.generated_pool
12
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
13
13
  pool.add_serialized_file(descriptor_data)
14
14
 
15
15
  module Temporalio