amit-temporalio 0.3.0-arm64-darwin

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 (175) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +2 -0
  3. data/Gemfile +23 -0
  4. data/Rakefile +101 -0
  5. data/lib/temporalio/activity/complete_async_error.rb +11 -0
  6. data/lib/temporalio/activity/context.rb +116 -0
  7. data/lib/temporalio/activity/definition.rb +189 -0
  8. data/lib/temporalio/activity/info.rb +64 -0
  9. data/lib/temporalio/activity.rb +12 -0
  10. data/lib/temporalio/api/activity/v1/message.rb +25 -0
  11. data/lib/temporalio/api/batch/v1/message.rb +31 -0
  12. data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
  13. data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +126 -0
  14. data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +25 -0
  15. data/lib/temporalio/api/cloud/cloudservice.rb +3 -0
  16. data/lib/temporalio/api/cloud/identity/v1/message.rb +41 -0
  17. data/lib/temporalio/api/cloud/namespace/v1/message.rb +42 -0
  18. data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
  19. data/lib/temporalio/api/cloud/operation/v1/message.rb +28 -0
  20. data/lib/temporalio/api/cloud/region/v1/message.rb +24 -0
  21. data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
  22. data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
  23. data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
  24. data/lib/temporalio/api/command/v1/message.rb +46 -0
  25. data/lib/temporalio/api/common/v1/grpc_status.rb +23 -0
  26. data/lib/temporalio/api/common/v1/message.rb +47 -0
  27. data/lib/temporalio/api/enums/v1/batch_operation.rb +22 -0
  28. data/lib/temporalio/api/enums/v1/command_type.rb +21 -0
  29. data/lib/temporalio/api/enums/v1/common.rb +26 -0
  30. data/lib/temporalio/api/enums/v1/event_type.rb +21 -0
  31. data/lib/temporalio/api/enums/v1/failed_cause.rb +26 -0
  32. data/lib/temporalio/api/enums/v1/namespace.rb +23 -0
  33. data/lib/temporalio/api/enums/v1/query.rb +22 -0
  34. data/lib/temporalio/api/enums/v1/reset.rb +23 -0
  35. data/lib/temporalio/api/enums/v1/schedule.rb +21 -0
  36. data/lib/temporalio/api/enums/v1/task_queue.rb +25 -0
  37. data/lib/temporalio/api/enums/v1/update.rb +22 -0
  38. data/lib/temporalio/api/enums/v1/workflow.rb +30 -0
  39. data/lib/temporalio/api/errordetails/v1/message.rb +42 -0
  40. data/lib/temporalio/api/export/v1/message.rb +24 -0
  41. data/lib/temporalio/api/failure/v1/message.rb +35 -0
  42. data/lib/temporalio/api/filter/v1/message.rb +27 -0
  43. data/lib/temporalio/api/history/v1/message.rb +90 -0
  44. data/lib/temporalio/api/namespace/v1/message.rb +31 -0
  45. data/lib/temporalio/api/nexus/v1/message.rb +40 -0
  46. data/lib/temporalio/api/operatorservice/v1/request_response.rb +49 -0
  47. data/lib/temporalio/api/operatorservice/v1/service.rb +23 -0
  48. data/lib/temporalio/api/operatorservice.rb +3 -0
  49. data/lib/temporalio/api/payload_visitor.rb +1513 -0
  50. data/lib/temporalio/api/protocol/v1/message.rb +23 -0
  51. data/lib/temporalio/api/query/v1/message.rb +27 -0
  52. data/lib/temporalio/api/replication/v1/message.rb +26 -0
  53. data/lib/temporalio/api/schedule/v1/message.rb +43 -0
  54. data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +25 -0
  55. data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +21 -0
  56. data/lib/temporalio/api/sdk/v1/user_metadata.rb +23 -0
  57. data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +23 -0
  58. data/lib/temporalio/api/taskqueue/v1/message.rb +45 -0
  59. data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
  60. data/lib/temporalio/api/testservice/v1/service.rb +23 -0
  61. data/lib/temporalio/api/update/v1/message.rb +33 -0
  62. data/lib/temporalio/api/version/v1/message.rb +26 -0
  63. data/lib/temporalio/api/workflow/v1/message.rb +43 -0
  64. data/lib/temporalio/api/workflowservice/v1/request_response.rb +204 -0
  65. data/lib/temporalio/api/workflowservice/v1/service.rb +23 -0
  66. data/lib/temporalio/api/workflowservice.rb +3 -0
  67. data/lib/temporalio/api.rb +14 -0
  68. data/lib/temporalio/cancellation.rb +170 -0
  69. data/lib/temporalio/client/activity_id_reference.rb +32 -0
  70. data/lib/temporalio/client/async_activity_handle.rb +85 -0
  71. data/lib/temporalio/client/connection/cloud_service.rb +726 -0
  72. data/lib/temporalio/client/connection/operator_service.rb +201 -0
  73. data/lib/temporalio/client/connection/service.rb +42 -0
  74. data/lib/temporalio/client/connection/test_service.rb +111 -0
  75. data/lib/temporalio/client/connection/workflow_service.rb +1041 -0
  76. data/lib/temporalio/client/connection.rb +316 -0
  77. data/lib/temporalio/client/interceptor.rb +416 -0
  78. data/lib/temporalio/client/schedule.rb +967 -0
  79. data/lib/temporalio/client/schedule_handle.rb +126 -0
  80. data/lib/temporalio/client/workflow_execution.rb +100 -0
  81. data/lib/temporalio/client/workflow_execution_count.rb +36 -0
  82. data/lib/temporalio/client/workflow_execution_status.rb +18 -0
  83. data/lib/temporalio/client/workflow_handle.rb +389 -0
  84. data/lib/temporalio/client/workflow_query_reject_condition.rb +14 -0
  85. data/lib/temporalio/client/workflow_update_handle.rb +65 -0
  86. data/lib/temporalio/client/workflow_update_wait_stage.rb +17 -0
  87. data/lib/temporalio/client.rb +484 -0
  88. data/lib/temporalio/common_enums.rb +41 -0
  89. data/lib/temporalio/converters/data_converter.rb +99 -0
  90. data/lib/temporalio/converters/failure_converter.rb +202 -0
  91. data/lib/temporalio/converters/payload_codec.rb +26 -0
  92. data/lib/temporalio/converters/payload_converter/binary_null.rb +34 -0
  93. data/lib/temporalio/converters/payload_converter/binary_plain.rb +35 -0
  94. data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +42 -0
  95. data/lib/temporalio/converters/payload_converter/composite.rb +66 -0
  96. data/lib/temporalio/converters/payload_converter/encoding.rb +35 -0
  97. data/lib/temporalio/converters/payload_converter/json_plain.rb +44 -0
  98. data/lib/temporalio/converters/payload_converter/json_protobuf.rb +41 -0
  99. data/lib/temporalio/converters/payload_converter.rb +71 -0
  100. data/lib/temporalio/converters/raw_value.rb +20 -0
  101. data/lib/temporalio/converters.rb +9 -0
  102. data/lib/temporalio/error/failure.rb +219 -0
  103. data/lib/temporalio/error.rb +155 -0
  104. data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +34 -0
  105. data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +31 -0
  106. data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +33 -0
  107. data/lib/temporalio/internal/bridge/api/common/common.rb +26 -0
  108. data/lib/temporalio/internal/bridge/api/core_interface.rb +40 -0
  109. data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +27 -0
  110. data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
  111. data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +56 -0
  112. data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +57 -0
  113. data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +30 -0
  114. data/lib/temporalio/internal/bridge/api.rb +3 -0
  115. data/lib/temporalio/internal/bridge/client.rb +95 -0
  116. data/lib/temporalio/internal/bridge/runtime.rb +53 -0
  117. data/lib/temporalio/internal/bridge/temporalio_bridge.bundle +0 -0
  118. data/lib/temporalio/internal/bridge/testing.rb +66 -0
  119. data/lib/temporalio/internal/bridge/worker.rb +85 -0
  120. data/lib/temporalio/internal/bridge.rb +36 -0
  121. data/lib/temporalio/internal/client/implementation.rb +700 -0
  122. data/lib/temporalio/internal/metric.rb +122 -0
  123. data/lib/temporalio/internal/proto_utils.rb +133 -0
  124. data/lib/temporalio/internal/worker/activity_worker.rb +376 -0
  125. data/lib/temporalio/internal/worker/multi_runner.rb +213 -0
  126. data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
  127. data/lib/temporalio/internal/worker/workflow_instance/context.rb +333 -0
  128. data/lib/temporalio/internal/worker/workflow_instance/details.rb +44 -0
  129. data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
  130. data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
  131. data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
  132. data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
  133. data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
  134. data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
  135. data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +415 -0
  136. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
  137. data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
  138. data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +163 -0
  139. data/lib/temporalio/internal/worker/workflow_instance.rb +730 -0
  140. data/lib/temporalio/internal/worker/workflow_worker.rb +236 -0
  141. data/lib/temporalio/internal.rb +7 -0
  142. data/lib/temporalio/metric.rb +109 -0
  143. data/lib/temporalio/retry_policy.rb +74 -0
  144. data/lib/temporalio/runtime.rb +314 -0
  145. data/lib/temporalio/scoped_logger.rb +96 -0
  146. data/lib/temporalio/search_attributes.rb +343 -0
  147. data/lib/temporalio/testing/activity_environment.rb +136 -0
  148. data/lib/temporalio/testing/workflow_environment.rb +383 -0
  149. data/lib/temporalio/testing.rb +10 -0
  150. data/lib/temporalio/version.rb +5 -0
  151. data/lib/temporalio/worker/activity_executor/fiber.rb +49 -0
  152. data/lib/temporalio/worker/activity_executor/thread_pool.rb +46 -0
  153. data/lib/temporalio/worker/activity_executor.rb +55 -0
  154. data/lib/temporalio/worker/interceptor.rb +362 -0
  155. data/lib/temporalio/worker/thread_pool.rb +237 -0
  156. data/lib/temporalio/worker/tuner.rb +189 -0
  157. data/lib/temporalio/worker/workflow_executor/thread_pool.rb +230 -0
  158. data/lib/temporalio/worker/workflow_executor.rb +26 -0
  159. data/lib/temporalio/worker/workflow_replayer.rb +343 -0
  160. data/lib/temporalio/worker.rb +569 -0
  161. data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
  162. data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
  163. data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
  164. data/lib/temporalio/workflow/definition.rb +566 -0
  165. data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
  166. data/lib/temporalio/workflow/future.rb +151 -0
  167. data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
  168. data/lib/temporalio/workflow/info.rb +82 -0
  169. data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
  170. data/lib/temporalio/workflow/update_info.rb +20 -0
  171. data/lib/temporalio/workflow.rb +529 -0
  172. data/lib/temporalio/workflow_history.rb +47 -0
  173. data/lib/temporalio.rb +11 -0
  174. data/temporalio.gemspec +28 -0
  175. metadata +236 -0
@@ -0,0 +1,343 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/api'
4
+
5
+ module Temporalio
6
+ # Collection of typed search attributes.
7
+ #
8
+ # This is represented as a mapping of {SearchAttributes::Key} to object values. This is not a hash though it does have
9
+ # a few hash-like methods and can be converted to a hash via {#to_h}. In some situations, such as in workflows, this
10
+ # class is immutable for outside use.
11
+ class SearchAttributes
12
+ # Key for a search attribute.
13
+ class Key
14
+ # @return [String] Name of the search attribute.
15
+ attr_reader :name
16
+
17
+ # @return [IndexedValueType] Type of the search attribute.
18
+ attr_reader :type
19
+
20
+ def initialize(name, type)
21
+ raise ArgumentError, 'Invalid type' unless Api::Enums::V1::IndexedValueType.lookup(type)
22
+
23
+ @name = name.to_s
24
+ @type = type
25
+ end
26
+
27
+ # @return [Boolean] Check equality.
28
+ def ==(other)
29
+ other.is_a?(Key) && other.name == @name && other.type == @type
30
+ end
31
+
32
+ alias eql? ==
33
+
34
+ # @return [Integer] Hash
35
+ def hash
36
+ [self.class, @name, @age].hash
37
+ end
38
+
39
+ # Validate that the given value matches the expected {#type}.
40
+ #
41
+ # @raise [TypeError] The value does not have the proper type.
42
+ def validate_value(value)
43
+ case type
44
+ when IndexedValueType::TEXT
45
+ raise TypeError, 'Value of TEXT key must be a String' unless value.is_a?(String)
46
+ when IndexedValueType::KEYWORD
47
+ raise TypeError, 'Value of KEYWORD key must be a String' unless value.is_a?(String)
48
+ when IndexedValueType::INTEGER
49
+ raise TypeError, 'Value of INTEGER key must be a Integer' unless value.is_a?(Integer)
50
+ when IndexedValueType::FLOAT
51
+ unless value.is_a?(Float) || value.is_a?(Integer)
52
+ raise TypeError, 'Value of FLOAT key must be a Float or Integer'
53
+ end
54
+ when IndexedValueType::BOOLEAN
55
+ unless value.is_a?(TrueClass) || value.is_a?(FalseClass)
56
+ raise TypeError, 'Value of BOOLEAN key must be a Boolean'
57
+ end
58
+ when IndexedValueType::TIME
59
+ raise TypeError, 'Value of TIME key must be a Time' unless value.is_a?(Time)
60
+ when IndexedValueType::KEYWORD_LIST
61
+ unless value.is_a?(Array) && value.all? { |v| v.is_a?(String) }
62
+ raise TypeError, 'Value of KEYWORD_LIST key must be an Array of String'
63
+ end
64
+ else
65
+ # Should never happen, checked in constructor
66
+ raise 'Unrecognized key type'
67
+ end
68
+ end
69
+
70
+ # Create an updated that sets the given value for this key.
71
+ #
72
+ # @param value [Object] Value to update. Must be the proper type for the key.
73
+ # @return [Update] Created update.
74
+ def value_set(value)
75
+ raise ArgumentError, 'Value cannot be nil, use value_unset' if value.nil?
76
+
77
+ Update.new(self, value)
78
+ end
79
+
80
+ # Create an updated that unsets the key.
81
+ #
82
+ # @return [Update] Created update.
83
+ def value_unset
84
+ Update.new(self, nil)
85
+ end
86
+ end
87
+
88
+ # Search attribute update that can be separately applied.
89
+ class Update
90
+ # @return [Key] Key this update applies to.
91
+ attr_reader :key
92
+
93
+ # @return [Object, nil] Value to update or `nil` to remove the key.
94
+ attr_reader :value
95
+
96
+ # Create an update. Users may find it easier to use {Key#value_set} and {Key#value_unset} instead.
97
+ #
98
+ # @param key [Key] Key to update.
99
+ # @param value [Object, nil] Value to update to or nil to remove the value.
100
+ def initialize(key, value)
101
+ raise ArgumentError, 'Key must be a key' unless key.is_a?(Key)
102
+
103
+ key.validate_value(value) unless value.nil?
104
+ @key = key
105
+ @value = value
106
+ end
107
+
108
+ # @!visibility private
109
+ def _to_proto_pair
110
+ SearchAttributes._to_proto_pair(key, value)
111
+ end
112
+ end
113
+
114
+ # @!visibility private
115
+ def self._from_proto(proto, disable_mutations: false, never_nil: false)
116
+ return nil unless proto || never_nil
117
+
118
+ attrs = if proto
119
+ unless proto.is_a?(Api::Common::V1::SearchAttributes)
120
+ raise ArgumentError, 'Expected proto search attribute'
121
+ end
122
+
123
+ SearchAttributes.new(proto.indexed_fields.map do |key_name, payload| # rubocop:disable Style/MapToHash
124
+ key = Key.new(key_name, IndexedValueType::PROTO_VALUES[payload.metadata['type']])
125
+ value = _value_from_payload(payload)
126
+ [key, value]
127
+ end.to_h)
128
+ else
129
+ SearchAttributes.new
130
+ end
131
+ attrs._disable_mutations = disable_mutations
132
+ attrs
133
+ end
134
+
135
+ # @!visibility private
136
+ def self._value_from_payload(payload)
137
+ value = Converters::PayloadConverter.default.from_payload(payload)
138
+ # Time needs to be converted
139
+ value = Time.iso8601(value) if payload.metadata['type'] == 'DateTime' && value.is_a?(String)
140
+ value
141
+ end
142
+
143
+ # @!visibility private
144
+ def self._to_proto_pair(key, value)
145
+ # We use a default converter, but if type is a time, we need ISO format
146
+ value = value.iso8601 if key.type == IndexedValueType::TIME && value.is_a?(Time)
147
+
148
+ # Convert to payload
149
+ payload = Converters::PayloadConverter.default.to_payload(value)
150
+ payload.metadata['type'] = IndexedValueType::PROTO_NAMES[key.type]
151
+
152
+ [key.name, payload]
153
+ end
154
+
155
+ # Create a search attribute collection.
156
+ #
157
+ # @param existing [SearchAttributes, Hash<Key, Object>, nil] Existing collection. This can be another
158
+ # {SearchAttributes} instance or a {::Hash}.
159
+ def initialize(existing = nil)
160
+ if existing.nil?
161
+ @raw_hash = {}
162
+ elsif existing.is_a?(SearchAttributes)
163
+ @raw_hash = existing.to_h
164
+ elsif existing.is_a?(Hash)
165
+ @raw_hash = {}
166
+ existing.each { |key, value| self[key] = value }
167
+ else
168
+ raise ArgumentError, 'Existing must be nil, a SearchAttributes instance, or a valid Hash'
169
+ end
170
+ end
171
+
172
+ # Set a search attribute value for a key. This will replace any existing value for the {Key#name }regardless of
173
+ # {Key#type}.
174
+ #
175
+ # @param key [Key] A key to set. This must be a {Key} and the value must be proper for the {Key#type}.
176
+ # @param value [Object, nil] The value to set. If `nil`, the key is removed. The value must be proper for the `key`.
177
+ def []=(key, value)
178
+ _assert_mutations_enabled
179
+ # Key must be a Key
180
+ raise ArgumentError, 'Key must be a key' unless key.is_a?(Key)
181
+
182
+ key.validate_value(value) unless value.nil?
183
+
184
+ # Remove any key with the same name and set
185
+ delete(key)
186
+ # We only set the value if it's non-nil, otherwise it's a delete
187
+ @raw_hash[key] = value unless value.nil?
188
+ end
189
+
190
+ # Get a search attribute value for a key.
191
+ #
192
+ # @param key [Key, String, Symbol] The key to find. If this is a {Key}, it will use key equality (i.e. name and
193
+ # type) to search. If this is a {::String}, the type is not checked when finding the proper key.
194
+ # @return [Object, nil] Value if found or `nil` if not.
195
+ def [](key)
196
+ # Key must be a Key or a string
197
+ case key
198
+ when Key
199
+ @raw_hash[key]
200
+ when String, Symbol
201
+ @raw_hash.find { |hash_key, _| hash_key.name == key.to_s }&.last
202
+ else
203
+ raise ArgumentError, 'Key must be a key or string/symbol'
204
+ end
205
+ end
206
+
207
+ # Delete a search attribute key
208
+ #
209
+ # @param key [Key, String, Symbol] The key to delete. Regardless of whether this is a {Key} or a {::String}, the key
210
+ # with the matching name will be deleted. This means a {Key} with a matching name but different type may be
211
+ # deleted.
212
+ def delete(key)
213
+ _assert_mutations_enabled
214
+ # Key must be a Key or a string, but we delete all values for the
215
+ # name no matter what
216
+ name = case key
217
+ when Key
218
+ key.name
219
+ when String, Symbol
220
+ key.to_s
221
+ else
222
+ raise ArgumentError, 'Key must be a key or string/symbol'
223
+ end
224
+ @raw_hash.delete_if { |hash_key, _| hash_key.name == name }
225
+ end
226
+
227
+ # Like {::Hash#each}.
228
+ def each(&)
229
+ @raw_hash.each(&)
230
+ end
231
+
232
+ # @return [Hash<Key, Object>] Copy of the search attributes as a hash.
233
+ def to_h
234
+ @raw_hash.dup
235
+ end
236
+
237
+ # @return [SearchAttributes] Copy of the search attributes.
238
+ def dup
239
+ attrs = SearchAttributes.new(self)
240
+ attrs._disable_mutations = false
241
+ attrs
242
+ end
243
+
244
+ # @return [Boolean] Whether the set of attributes is empty.
245
+ def empty?
246
+ length.zero?
247
+ end
248
+
249
+ # @return [Integer] Number of attributes.
250
+ def length
251
+ @raw_hash.length
252
+ end
253
+
254
+ alias size length
255
+
256
+ # Return a new search attributes collection with updates applied.
257
+ #
258
+ # @param updates [Update] Updates created via {Key#value_set} or {Key#value_unset}.
259
+ # @return [SearchAttributes] New collection.
260
+ def update(*updates)
261
+ _assert_mutations_enabled
262
+ attrs = dup
263
+ attrs.update!(*updates)
264
+ attrs
265
+ end
266
+
267
+ # Update this search attribute collection with given updates.
268
+ #
269
+ # @param updates [Update] Updates created via {Key#value_set} or {Key#value_unset}.
270
+ def update!(*updates)
271
+ _assert_mutations_enabled
272
+ updates.each do |update|
273
+ raise ArgumentError, 'Update must be an update' unless update.is_a?(Update)
274
+
275
+ if update.value.nil?
276
+ delete(update.key)
277
+ else
278
+ self[update.key] = update.value
279
+ end
280
+ end
281
+ end
282
+
283
+ # @!visibility private
284
+ def _to_proto
285
+ Api::Common::V1::SearchAttributes.new(indexed_fields: _to_proto_hash)
286
+ end
287
+
288
+ # @!visibility private
289
+ def _to_proto_hash
290
+ @raw_hash.to_h { |key, value| SearchAttributes._to_proto_pair(key, value) }
291
+ end
292
+
293
+ # @!visibility private
294
+ def _assert_mutations_enabled
295
+ raise 'Search attribute mutations disabled' if @disable_mutations
296
+ end
297
+
298
+ # @!visibility private
299
+ def _disable_mutations=(value)
300
+ @disable_mutations = value
301
+ end
302
+
303
+ # Type for a search attribute key/value.
304
+ #
305
+ # @see https://docs.temporal.io/visibility#supported-types
306
+ module IndexedValueType
307
+ # Text type, values must be {::String}.
308
+ TEXT = Api::Enums::V1::IndexedValueType::INDEXED_VALUE_TYPE_TEXT
309
+
310
+ # Keyword type, values must be {::String}.
311
+ KEYWORD = Api::Enums::V1::IndexedValueType::INDEXED_VALUE_TYPE_KEYWORD
312
+
313
+ # Integer type, values must be {::Integer}.
314
+ INTEGER = Api::Enums::V1::IndexedValueType::INDEXED_VALUE_TYPE_INT
315
+
316
+ # Float type, values must be {::Float} or {::Integer}.
317
+ FLOAT = Api::Enums::V1::IndexedValueType::INDEXED_VALUE_TYPE_DOUBLE
318
+
319
+ # Boolean type, values must be {::TrueClass} or {::FalseClass}.
320
+ BOOLEAN = Api::Enums::V1::IndexedValueType::INDEXED_VALUE_TYPE_BOOL
321
+
322
+ # Time type, values must be {::Time}.
323
+ TIME = Api::Enums::V1::IndexedValueType::INDEXED_VALUE_TYPE_DATETIME
324
+
325
+ # Keyword list type, values must be {::Array<String>}.
326
+ KEYWORD_LIST = Api::Enums::V1::IndexedValueType::INDEXED_VALUE_TYPE_KEYWORD_LIST
327
+
328
+ # @!visibility private
329
+ PROTO_NAMES = {
330
+ TEXT => 'Text',
331
+ KEYWORD => 'Keyword',
332
+ INTEGER => 'Int',
333
+ FLOAT => 'Double',
334
+ BOOLEAN => 'Bool',
335
+ TIME => 'DateTime',
336
+ KEYWORD_LIST => 'KeywordList'
337
+ }.freeze
338
+
339
+ # @!visibility private
340
+ PROTO_VALUES = PROTO_NAMES.invert.freeze
341
+ end
342
+ end
343
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temporalio/activity'
4
+ require 'temporalio/cancellation'
5
+ require 'temporalio/converters/payload_converter'
6
+ require 'temporalio/worker/activity_executor'
7
+
8
+ module Temporalio
9
+ module Testing
10
+ # Test environment for testing activities.
11
+ #
12
+ # Users can create this environment and then use {run} to execute activities on it. Often, since mutable things like
13
+ # cancellation can be set, users create this for each activity that is run. There is no real performance penalty for
14
+ # creating an environment for every run.
15
+ class ActivityEnvironment
16
+ # @return [Activity::Info] The activity info used by default. This is frozen, but can be dup'd and mutated to pass
17
+ # in to {initialize}.
18
+ def self.default_info
19
+ @default_info ||= Activity::Info.new(
20
+ activity_id: 'test',
21
+ activity_type: 'unknown',
22
+ attempt: 1,
23
+ current_attempt_scheduled_time: Time.at(0),
24
+ heartbeat_details: [],
25
+ heartbeat_timeout: nil,
26
+ local?: false,
27
+ schedule_to_close_timeout: 1.0,
28
+ scheduled_time: Time.at(0),
29
+ start_to_close_timeout: 1.0,
30
+ started_time: Time.at(0),
31
+ task_queue: 'test',
32
+ task_token: String.new('test', encoding: Encoding::ASCII_8BIT),
33
+ workflow_id: 'test',
34
+ workflow_namespace: 'default',
35
+ workflow_run_id: 'test-run',
36
+ workflow_type: 'test'
37
+ ).freeze
38
+ end
39
+
40
+ # Create a test environment for activities.
41
+ #
42
+ # @param info [Activity::Info] Value for {Activity::Context#info}.
43
+ # @param on_heartbeat [Proc(Array), nil] Proc that is called with all heartbeat details when
44
+ # {Activity::Context#heartbeat} is called.
45
+ # @param cancellation [Cancellation] Value for {Activity::Context#cancellation}.
46
+ # @param worker_shutdown_cancellation [Cancellation] Value for {Activity::Context#worker_shutdown_cancellation}.
47
+ # @param payload_converter [Converters::PayloadConverter] Value for {Activity::Context#payload_converter}.
48
+ # @param logger [Logger] Value for {Activity::Context#logger}.
49
+ # @param activity_executors [Hash<Symbol, Worker::ActivityExecutor>] Executors that activities can run within.
50
+ def initialize(
51
+ info: ActivityEnvironment.default_info,
52
+ on_heartbeat: nil,
53
+ cancellation: Cancellation.new,
54
+ worker_shutdown_cancellation: Cancellation.new,
55
+ payload_converter: Converters::PayloadConverter.default,
56
+ logger: Logger.new(nil),
57
+ activity_executors: Worker::ActivityExecutor.defaults
58
+ )
59
+ @info = info
60
+ @on_heartbeat = on_heartbeat
61
+ @cancellation = cancellation
62
+ @worker_shutdown_cancellation = worker_shutdown_cancellation
63
+ @payload_converter = payload_converter
64
+ @logger = logger
65
+ @activity_executors = activity_executors
66
+ end
67
+
68
+ # Run an activity and returns its result or raises its exception.
69
+ #
70
+ # @param activity [Activity::Definition, Class<Activity::Definition>, Activity::Definition::Info] Activity to run.
71
+ # @param args [Array<Object>] Arguments to the activity.
72
+ # @return Activity result.
73
+ def run(activity, *args)
74
+ defn = Activity::Definition::Info.from_activity(activity)
75
+ executor = @activity_executors[defn.executor]
76
+ raise ArgumentError, "Unknown executor: #{defn.executor}" if executor.nil?
77
+
78
+ queue = Queue.new
79
+ executor.execute_activity(defn) do
80
+ Activity::Context._current_executor = executor
81
+ executor.set_activity_context(defn, Context.new(
82
+ info: @info.dup,
83
+ instance:
84
+ defn.instance.is_a?(Proc) ? defn.instance.call : defn.instance,
85
+ on_heartbeat: @on_heartbeat,
86
+ cancellation: @cancellation,
87
+ worker_shutdown_cancellation: @worker_shutdown_cancellation,
88
+ payload_converter: @payload_converter,
89
+ logger: @logger
90
+ ))
91
+ queue.push([defn.proc.call(*args), nil])
92
+ rescue Exception => e # rubocop:disable Lint/RescueException Intentionally capturing all exceptions
93
+ queue.push([nil, e])
94
+ ensure
95
+ executor.set_activity_context(defn, nil)
96
+ Activity::Context._current_executor = nil
97
+ end
98
+
99
+ result, err = queue.pop
100
+ raise err unless err.nil?
101
+
102
+ result
103
+ end
104
+
105
+ # @!visibility private
106
+ class Context < Activity::Context
107
+ attr_reader :info, :instance, :cancellation, :worker_shutdown_cancellation, :payload_converter, :logger
108
+
109
+ def initialize( # rubocop:disable Lint/MissingSuper
110
+ info:,
111
+ instance:,
112
+ on_heartbeat:,
113
+ cancellation:,
114
+ worker_shutdown_cancellation:,
115
+ payload_converter:,
116
+ logger:
117
+ )
118
+ @info = info
119
+ @instance = instance
120
+ @on_heartbeat = on_heartbeat
121
+ @cancellation = cancellation
122
+ @worker_shutdown_cancellation = worker_shutdown_cancellation
123
+ @payload_converter = payload_converter
124
+ @logger = logger
125
+ end
126
+
127
+ # @!visibility private
128
+ def heartbeat(*details)
129
+ @on_heartbeat&.call(details)
130
+ end
131
+ end
132
+
133
+ private_constant :Context
134
+ end
135
+ end
136
+ end