amit-temporalio 0.3.1-x86_64-linux-musl
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.
- checksums.yaml +7 -0
- data/.yardopts +2 -0
- data/Gemfile +23 -0
- data/Rakefile +101 -0
- data/lib/temporalio/activity/complete_async_error.rb +11 -0
- data/lib/temporalio/activity/context.rb +116 -0
- data/lib/temporalio/activity/definition.rb +189 -0
- data/lib/temporalio/activity/info.rb +64 -0
- data/lib/temporalio/activity.rb +12 -0
- data/lib/temporalio/api/activity/v1/message.rb +25 -0
- data/lib/temporalio/api/batch/v1/message.rb +31 -0
- data/lib/temporalio/api/cloud/account/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +126 -0
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +25 -0
- data/lib/temporalio/api/cloud/cloudservice.rb +3 -0
- data/lib/temporalio/api/cloud/identity/v1/message.rb +41 -0
- data/lib/temporalio/api/cloud/namespace/v1/message.rb +42 -0
- data/lib/temporalio/api/cloud/nexus/v1/message.rb +31 -0
- data/lib/temporalio/api/cloud/operation/v1/message.rb +28 -0
- data/lib/temporalio/api/cloud/region/v1/message.rb +24 -0
- data/lib/temporalio/api/cloud/resource/v1/message.rb +23 -0
- data/lib/temporalio/api/cloud/sink/v1/message.rb +24 -0
- data/lib/temporalio/api/cloud/usage/v1/message.rb +31 -0
- data/lib/temporalio/api/command/v1/message.rb +46 -0
- data/lib/temporalio/api/common/v1/grpc_status.rb +23 -0
- data/lib/temporalio/api/common/v1/message.rb +47 -0
- data/lib/temporalio/api/enums/v1/batch_operation.rb +22 -0
- data/lib/temporalio/api/enums/v1/command_type.rb +21 -0
- data/lib/temporalio/api/enums/v1/common.rb +26 -0
- data/lib/temporalio/api/enums/v1/event_type.rb +21 -0
- data/lib/temporalio/api/enums/v1/failed_cause.rb +26 -0
- data/lib/temporalio/api/enums/v1/namespace.rb +23 -0
- data/lib/temporalio/api/enums/v1/query.rb +22 -0
- data/lib/temporalio/api/enums/v1/reset.rb +23 -0
- data/lib/temporalio/api/enums/v1/schedule.rb +21 -0
- data/lib/temporalio/api/enums/v1/task_queue.rb +25 -0
- data/lib/temporalio/api/enums/v1/update.rb +22 -0
- data/lib/temporalio/api/enums/v1/workflow.rb +30 -0
- data/lib/temporalio/api/errordetails/v1/message.rb +42 -0
- data/lib/temporalio/api/export/v1/message.rb +24 -0
- data/lib/temporalio/api/failure/v1/message.rb +35 -0
- data/lib/temporalio/api/filter/v1/message.rb +27 -0
- data/lib/temporalio/api/history/v1/message.rb +90 -0
- data/lib/temporalio/api/namespace/v1/message.rb +31 -0
- data/lib/temporalio/api/nexus/v1/message.rb +40 -0
- data/lib/temporalio/api/operatorservice/v1/request_response.rb +49 -0
- data/lib/temporalio/api/operatorservice/v1/service.rb +23 -0
- data/lib/temporalio/api/operatorservice.rb +3 -0
- data/lib/temporalio/api/payload_visitor.rb +1513 -0
- data/lib/temporalio/api/protocol/v1/message.rb +23 -0
- data/lib/temporalio/api/query/v1/message.rb +27 -0
- data/lib/temporalio/api/replication/v1/message.rb +26 -0
- data/lib/temporalio/api/schedule/v1/message.rb +43 -0
- data/lib/temporalio/api/sdk/v1/enhanced_stack_trace.rb +25 -0
- data/lib/temporalio/api/sdk/v1/task_complete_metadata.rb +21 -0
- data/lib/temporalio/api/sdk/v1/user_metadata.rb +23 -0
- data/lib/temporalio/api/sdk/v1/workflow_metadata.rb +23 -0
- data/lib/temporalio/api/taskqueue/v1/message.rb +45 -0
- data/lib/temporalio/api/testservice/v1/request_response.rb +31 -0
- data/lib/temporalio/api/testservice/v1/service.rb +23 -0
- data/lib/temporalio/api/update/v1/message.rb +33 -0
- data/lib/temporalio/api/version/v1/message.rb +26 -0
- data/lib/temporalio/api/workflow/v1/message.rb +43 -0
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +204 -0
- data/lib/temporalio/api/workflowservice/v1/service.rb +23 -0
- data/lib/temporalio/api/workflowservice.rb +3 -0
- data/lib/temporalio/api.rb +14 -0
- data/lib/temporalio/cancellation.rb +170 -0
- data/lib/temporalio/client/activity_id_reference.rb +32 -0
- data/lib/temporalio/client/async_activity_handle.rb +85 -0
- data/lib/temporalio/client/connection/cloud_service.rb +726 -0
- data/lib/temporalio/client/connection/operator_service.rb +201 -0
- data/lib/temporalio/client/connection/service.rb +42 -0
- data/lib/temporalio/client/connection/test_service.rb +111 -0
- data/lib/temporalio/client/connection/workflow_service.rb +1041 -0
- data/lib/temporalio/client/connection.rb +316 -0
- data/lib/temporalio/client/interceptor.rb +416 -0
- data/lib/temporalio/client/schedule.rb +967 -0
- data/lib/temporalio/client/schedule_handle.rb +126 -0
- data/lib/temporalio/client/workflow_execution.rb +100 -0
- data/lib/temporalio/client/workflow_execution_count.rb +36 -0
- data/lib/temporalio/client/workflow_execution_status.rb +18 -0
- data/lib/temporalio/client/workflow_handle.rb +389 -0
- data/lib/temporalio/client/workflow_query_reject_condition.rb +14 -0
- data/lib/temporalio/client/workflow_update_handle.rb +65 -0
- data/lib/temporalio/client/workflow_update_wait_stage.rb +17 -0
- data/lib/temporalio/client.rb +484 -0
- data/lib/temporalio/common_enums.rb +41 -0
- data/lib/temporalio/converters/data_converter.rb +99 -0
- data/lib/temporalio/converters/failure_converter.rb +202 -0
- data/lib/temporalio/converters/payload_codec.rb +26 -0
- data/lib/temporalio/converters/payload_converter/binary_null.rb +34 -0
- data/lib/temporalio/converters/payload_converter/binary_plain.rb +35 -0
- data/lib/temporalio/converters/payload_converter/binary_protobuf.rb +42 -0
- data/lib/temporalio/converters/payload_converter/composite.rb +66 -0
- data/lib/temporalio/converters/payload_converter/encoding.rb +35 -0
- data/lib/temporalio/converters/payload_converter/json_plain.rb +44 -0
- data/lib/temporalio/converters/payload_converter/json_protobuf.rb +41 -0
- data/lib/temporalio/converters/payload_converter.rb +71 -0
- data/lib/temporalio/converters/raw_value.rb +20 -0
- data/lib/temporalio/converters.rb +9 -0
- data/lib/temporalio/error/failure.rb +219 -0
- data/lib/temporalio/error.rb +155 -0
- data/lib/temporalio/internal/bridge/3.2/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/3.3/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/3.4/temporalio_bridge.so +0 -0
- data/lib/temporalio/internal/bridge/api/activity_result/activity_result.rb +34 -0
- data/lib/temporalio/internal/bridge/api/activity_task/activity_task.rb +31 -0
- data/lib/temporalio/internal/bridge/api/child_workflow/child_workflow.rb +33 -0
- data/lib/temporalio/internal/bridge/api/common/common.rb +26 -0
- data/lib/temporalio/internal/bridge/api/core_interface.rb +40 -0
- data/lib/temporalio/internal/bridge/api/external_data/external_data.rb +27 -0
- data/lib/temporalio/internal/bridge/api/nexus/nexus.rb +33 -0
- data/lib/temporalio/internal/bridge/api/workflow_activation/workflow_activation.rb +56 -0
- data/lib/temporalio/internal/bridge/api/workflow_commands/workflow_commands.rb +57 -0
- data/lib/temporalio/internal/bridge/api/workflow_completion/workflow_completion.rb +30 -0
- data/lib/temporalio/internal/bridge/api.rb +3 -0
- data/lib/temporalio/internal/bridge/client.rb +95 -0
- data/lib/temporalio/internal/bridge/runtime.rb +53 -0
- data/lib/temporalio/internal/bridge/testing.rb +66 -0
- data/lib/temporalio/internal/bridge/worker.rb +85 -0
- data/lib/temporalio/internal/bridge.rb +36 -0
- data/lib/temporalio/internal/client/implementation.rb +700 -0
- data/lib/temporalio/internal/metric.rb +122 -0
- data/lib/temporalio/internal/proto_utils.rb +133 -0
- data/lib/temporalio/internal/worker/activity_worker.rb +376 -0
- data/lib/temporalio/internal/worker/multi_runner.rb +213 -0
- data/lib/temporalio/internal/worker/workflow_instance/child_workflow_handle.rb +54 -0
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +333 -0
- data/lib/temporalio/internal/worker/workflow_instance/details.rb +44 -0
- data/lib/temporalio/internal/worker/workflow_instance/external_workflow_handle.rb +32 -0
- data/lib/temporalio/internal/worker/workflow_instance/externally_immutable_hash.rb +22 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_execution.rb +25 -0
- data/lib/temporalio/internal/worker/workflow_instance/handler_hash.rb +41 -0
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +97 -0
- data/lib/temporalio/internal/worker/workflow_instance/inbound_implementation.rb +62 -0
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +415 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_logger.rb +37 -0
- data/lib/temporalio/internal/worker/workflow_instance/replay_safe_metric.rb +40 -0
- data/lib/temporalio/internal/worker/workflow_instance/scheduler.rb +163 -0
- data/lib/temporalio/internal/worker/workflow_instance.rb +730 -0
- data/lib/temporalio/internal/worker/workflow_worker.rb +236 -0
- data/lib/temporalio/internal.rb +7 -0
- data/lib/temporalio/metric.rb +109 -0
- data/lib/temporalio/retry_policy.rb +74 -0
- data/lib/temporalio/runtime.rb +314 -0
- data/lib/temporalio/scoped_logger.rb +96 -0
- data/lib/temporalio/search_attributes.rb +343 -0
- data/lib/temporalio/testing/activity_environment.rb +136 -0
- data/lib/temporalio/testing/workflow_environment.rb +383 -0
- data/lib/temporalio/testing.rb +10 -0
- data/lib/temporalio/version.rb +5 -0
- data/lib/temporalio/worker/activity_executor/fiber.rb +49 -0
- data/lib/temporalio/worker/activity_executor/thread_pool.rb +46 -0
- data/lib/temporalio/worker/activity_executor.rb +55 -0
- data/lib/temporalio/worker/interceptor.rb +362 -0
- data/lib/temporalio/worker/thread_pool.rb +237 -0
- data/lib/temporalio/worker/tuner.rb +189 -0
- data/lib/temporalio/worker/workflow_executor/thread_pool.rb +230 -0
- data/lib/temporalio/worker/workflow_executor.rb +26 -0
- data/lib/temporalio/worker/workflow_replayer.rb +343 -0
- data/lib/temporalio/worker.rb +569 -0
- data/lib/temporalio/workflow/activity_cancellation_type.rb +20 -0
- data/lib/temporalio/workflow/child_workflow_cancellation_type.rb +21 -0
- data/lib/temporalio/workflow/child_workflow_handle.rb +43 -0
- data/lib/temporalio/workflow/definition.rb +566 -0
- data/lib/temporalio/workflow/external_workflow_handle.rb +41 -0
- data/lib/temporalio/workflow/future.rb +151 -0
- data/lib/temporalio/workflow/handler_unfinished_policy.rb +13 -0
- data/lib/temporalio/workflow/info.rb +82 -0
- data/lib/temporalio/workflow/parent_close_policy.rb +19 -0
- data/lib/temporalio/workflow/update_info.rb +20 -0
- data/lib/temporalio/workflow.rb +529 -0
- data/lib/temporalio/workflow_history.rb +47 -0
- data/lib/temporalio.rb +11 -0
- data/temporalio.gemspec +28 -0
- metadata +238 -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
|