temporalio 0.6.0-aarch64-linux-musl → 1.1.0-aarch64-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 +4 -4
- data/Gemfile +3 -0
- data/lib/temporalio/activity/info.rb +5 -0
- data/lib/temporalio/api/cloud/account/v1/message.rb +3 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/request_response.rb +5 -1
- data/lib/temporalio/api/cloud/cloudservice/v1/service.rb +1 -1
- data/lib/temporalio/api/cloud/sink/v1/message.rb +3 -1
- data/lib/temporalio/api/deployment/v1/message.rb +1 -1
- data/lib/temporalio/api/namespace/v1/message.rb +1 -1
- data/lib/temporalio/api/payload_visitor.rb +6 -0
- data/lib/temporalio/api/workflowservice/v1/request_response.rb +5 -1
- data/lib/temporalio/api/workflowservice/v1/service.rb +1 -1
- data/lib/temporalio/cancellation.rb +2 -2
- data/lib/temporalio/client/async_activity_handle.rb +1 -0
- data/lib/temporalio/client/connection/cloud_service.rb +30 -0
- data/lib/temporalio/client/connection/workflow_service.rb +30 -0
- data/lib/temporalio/client/connection.rb +14 -9
- data/lib/temporalio/client.rb +1 -1
- data/lib/temporalio/contrib/open_telemetry.rb +78 -25
- data/lib/temporalio/converters/payload_converter/composite.rb +1 -0
- data/lib/temporalio/converters/payload_converter/json_protobuf.rb +1 -1
- data/lib/temporalio/env_config.rb +343 -0
- data/lib/temporalio/error.rb +5 -1
- 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/workflow_activation/workflow_activation.rb +1 -1
- data/lib/temporalio/internal/bridge/runtime.rb +1 -0
- data/lib/temporalio/internal/bridge/worker.rb +54 -3
- data/lib/temporalio/internal/client/implementation.rb +7 -2
- data/lib/temporalio/internal/worker/activity_worker.rb +1 -0
- data/lib/temporalio/internal/worker/workflow_instance/context.rb +2 -0
- data/lib/temporalio/internal/worker/workflow_instance/illegal_call_tracer.rb +17 -10
- data/lib/temporalio/internal/worker/workflow_instance/outbound_implementation.rb +6 -5
- data/lib/temporalio/internal/worker/workflow_instance.rb +78 -80
- data/lib/temporalio/runtime.rb +16 -3
- data/lib/temporalio/testing/activity_environment.rb +1 -0
- data/lib/temporalio/version.rb +1 -1
- data/lib/temporalio/worker/interceptor.rb +1 -0
- data/lib/temporalio/worker/tuner.rb +183 -18
- data/lib/temporalio/worker/workflow_replayer.rb +4 -3
- data/lib/temporalio/worker.rb +4 -5
- data/lib/temporalio/workflow/info.rb +7 -0
- data/lib/temporalio/workflow.rb +6 -3
- metadata +3 -2
|
@@ -154,8 +154,9 @@ module Temporalio
|
|
|
154
154
|
# +localhost:7233+.
|
|
155
155
|
# @param api_key [String, nil] API key for Temporal. This becomes the +Authorization+ HTTP header with +"Bearer "+
|
|
156
156
|
# prepended. This is only set if RPC metadata doesn't already have an +authorization+ key.
|
|
157
|
-
# @param tls [Boolean, TLSOptions] If false, do not use TLS. If true, use system default TLS options. If TLS
|
|
158
|
-
# options are present, those TLS options will be used.
|
|
157
|
+
# @param tls [Boolean, TLSOptions, nil] If false, do not use TLS. If true, use system default TLS options. If TLS
|
|
158
|
+
# options are present, those TLS options will be used. If nil (the default), TLS will be auto-enabled if
|
|
159
|
+
# api_key is provided.
|
|
159
160
|
# @param rpc_metadata [Hash<String, String>] Headers to use for all calls to the server. Keys here can be
|
|
160
161
|
# overriden by per-call RPC metadata keys.
|
|
161
162
|
# @param rpc_retry [RPCRetryOptions] Retry options for direct service calls (when opted in) or all high-level
|
|
@@ -173,7 +174,7 @@ module Temporalio
|
|
|
173
174
|
def initialize(
|
|
174
175
|
target_host:,
|
|
175
176
|
api_key: nil,
|
|
176
|
-
tls:
|
|
177
|
+
tls: nil,
|
|
177
178
|
rpc_metadata: {},
|
|
178
179
|
rpc_retry: RPCRetryOptions.new,
|
|
179
180
|
identity: "#{Process.pid}@#{Socket.gethostname}",
|
|
@@ -285,13 +286,17 @@ module Temporalio
|
|
|
285
286
|
),
|
|
286
287
|
identity: @options.identity || "#{Process.pid}@#{Socket.gethostname}"
|
|
287
288
|
)
|
|
288
|
-
|
|
289
|
-
|
|
289
|
+
# Auto-enable TLS when API key is provided and tls not explicitly set
|
|
290
|
+
tls = @options.tls
|
|
291
|
+
tls = true if tls.nil? && @options.api_key
|
|
292
|
+
|
|
293
|
+
if tls
|
|
294
|
+
options.tls = if tls.is_a?(TLSOptions)
|
|
290
295
|
Internal::Bridge::Client::TLSOptions.new(
|
|
291
|
-
client_cert:
|
|
292
|
-
client_private_key:
|
|
293
|
-
server_root_ca_cert:
|
|
294
|
-
domain:
|
|
296
|
+
client_cert: tls.client_cert, # steep:ignore
|
|
297
|
+
client_private_key: tls.client_private_key, # steep:ignore
|
|
298
|
+
server_root_ca_cert: tls.server_root_ca_cert, # steep:ignore
|
|
299
|
+
domain: tls.domain # steep:ignore
|
|
295
300
|
)
|
|
296
301
|
else
|
|
297
302
|
Internal::Bridge::Client::TLSOptions.new
|
data/lib/temporalio/client.rb
CHANGED
|
@@ -86,10 +86,24 @@ module Temporalio
|
|
|
86
86
|
attributes: nil,
|
|
87
87
|
outbound_input: nil
|
|
88
88
|
)
|
|
89
|
-
tracer.in_span
|
|
89
|
+
# We cannot use tracer.in_span because it always assumes we want to set the status as error on exception, but
|
|
90
|
+
# we do not want to do that for benign exceptions. This is effectively a copy of the source of in_span with
|
|
91
|
+
# that change.
|
|
92
|
+
span = nil
|
|
93
|
+
span = tracer.start_span(name, attributes:, kind:)
|
|
94
|
+
::OpenTelemetry::Trace.with_span(span) do
|
|
90
95
|
_apply_context_to_headers(outbound_input.headers) if outbound_input
|
|
91
96
|
yield
|
|
92
97
|
end
|
|
98
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
99
|
+
span&.record_exception(e)
|
|
100
|
+
# Only set the status if it is not a benign application error
|
|
101
|
+
unless e.is_a?(Error::ApplicationError) && e.category == Error::ApplicationError::Category::BENIGN
|
|
102
|
+
span&.status = ::OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{e.class}")
|
|
103
|
+
end
|
|
104
|
+
raise e
|
|
105
|
+
ensure
|
|
106
|
+
span&.finish
|
|
93
107
|
end
|
|
94
108
|
|
|
95
109
|
# @!visibility private
|
|
@@ -217,7 +231,7 @@ module Temporalio
|
|
|
217
231
|
|
|
218
232
|
# @!visibility private
|
|
219
233
|
def execute(input)
|
|
220
|
-
|
|
234
|
+
_attach_context(Temporalio::Workflow.info.headers)
|
|
221
235
|
Workflow.with_completed_span("RunWorkflow:#{Temporalio::Workflow.info.workflow_type}", kind: :server) do
|
|
222
236
|
super
|
|
223
237
|
ensure
|
|
@@ -231,7 +245,7 @@ module Temporalio
|
|
|
231
245
|
|
|
232
246
|
# @!visibility private
|
|
233
247
|
def handle_signal(input)
|
|
234
|
-
|
|
248
|
+
_attach_context(Temporalio::Workflow.info.headers)
|
|
235
249
|
Workflow.with_completed_span(
|
|
236
250
|
"HandleSignal:#{input.signal}",
|
|
237
251
|
links: _links_from_headers(input.headers),
|
|
@@ -246,7 +260,7 @@ module Temporalio
|
|
|
246
260
|
|
|
247
261
|
# @!visibility private
|
|
248
262
|
def handle_query(input)
|
|
249
|
-
|
|
263
|
+
_attach_context(Temporalio::Workflow.info.headers)
|
|
250
264
|
Workflow.with_completed_span(
|
|
251
265
|
"HandleQuery:#{input.query}",
|
|
252
266
|
links: _links_from_headers(input.headers),
|
|
@@ -267,7 +281,7 @@ module Temporalio
|
|
|
267
281
|
|
|
268
282
|
# @!visibility private
|
|
269
283
|
def validate_update(input)
|
|
270
|
-
|
|
284
|
+
_attach_context(Temporalio::Workflow.info.headers)
|
|
271
285
|
Workflow.with_completed_span(
|
|
272
286
|
"ValidateUpdate:#{input.update}",
|
|
273
287
|
attributes: { 'temporalUpdateID' => input.id },
|
|
@@ -290,7 +304,7 @@ module Temporalio
|
|
|
290
304
|
|
|
291
305
|
# @!visibility private
|
|
292
306
|
def handle_update(input)
|
|
293
|
-
|
|
307
|
+
_attach_context(Temporalio::Workflow.info.headers)
|
|
294
308
|
Workflow.with_completed_span(
|
|
295
309
|
"HandleUpdate:#{input.update}",
|
|
296
310
|
attributes: { 'temporalUpdateID' => input.id },
|
|
@@ -309,14 +323,30 @@ module Temporalio
|
|
|
309
323
|
end
|
|
310
324
|
end
|
|
311
325
|
|
|
326
|
+
# @!visibility private
|
|
327
|
+
def _attach_context(headers)
|
|
328
|
+
# We have to disable the durable scheduler _even_ for something simple like attach context. For most OTel
|
|
329
|
+
# implementations, such a procedure is completely deterministic, but unfortunately some implementations like
|
|
330
|
+
# DataDog monkey patch OpenTelemetry (see
|
|
331
|
+
# https://github.com/DataDog/dd-trace-rb/blob/f88393d0571806b9980bb2cf5066eba60cfea177/lib/datadog/opentelemetry/api/context.rb#L184)
|
|
332
|
+
# to make even OpenTelemetry::Context.current non-deterministic because it uses mutexes. And a simple text
|
|
333
|
+
# map propagation extraction accesses Context.current.
|
|
334
|
+
Temporalio::Workflow::Unsafe.durable_scheduler_disabled do
|
|
335
|
+
@root._attach_context(headers)
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
312
339
|
# @!visibility private
|
|
313
340
|
def _links_from_headers(headers)
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
341
|
+
# See _attach_context above for why we have to disable scheduler even for these simple operations
|
|
342
|
+
Temporalio::Workflow::Unsafe.durable_scheduler_disabled do
|
|
343
|
+
context = @root._context_from_headers(headers)
|
|
344
|
+
span = ::OpenTelemetry::Trace.current_span(context) if context
|
|
345
|
+
if span && span != ::OpenTelemetry::Trace::Span::INVALID
|
|
346
|
+
[::OpenTelemetry::Trace::Link.new(span.context)]
|
|
347
|
+
else
|
|
348
|
+
[]
|
|
349
|
+
end
|
|
320
350
|
end
|
|
321
351
|
end
|
|
322
352
|
end
|
|
@@ -345,7 +375,9 @@ module Temporalio
|
|
|
345
375
|
# @!visibility private
|
|
346
376
|
def initialize_continue_as_new_error(input)
|
|
347
377
|
# Just apply the current context to headers
|
|
348
|
-
|
|
378
|
+
Temporalio::Workflow::Unsafe.durable_scheduler_disabled do
|
|
379
|
+
@root._apply_context_to_headers(input.error.headers)
|
|
380
|
+
end
|
|
349
381
|
super
|
|
350
382
|
end
|
|
351
383
|
|
|
@@ -372,7 +404,11 @@ module Temporalio
|
|
|
372
404
|
|
|
373
405
|
# @!visibility private
|
|
374
406
|
def _apply_span_to_headers(headers, span)
|
|
375
|
-
|
|
407
|
+
# See WorkflowInbound#_attach_context comments for why we have to disable scheduler even for these simple
|
|
408
|
+
# operations
|
|
409
|
+
Temporalio::Workflow::Unsafe.durable_scheduler_disabled do
|
|
410
|
+
@root._apply_context_to_headers(headers, context: ::OpenTelemetry::Trace.context_with_span(span)) if span
|
|
411
|
+
end
|
|
376
412
|
end
|
|
377
413
|
end
|
|
378
414
|
|
|
@@ -405,9 +441,19 @@ module Temporalio
|
|
|
405
441
|
)
|
|
406
442
|
span = completed_span(name, attributes:, links:, kind:, exception:, even_during_replay:)
|
|
407
443
|
if span
|
|
408
|
-
::OpenTelemetry::Trace.with_span
|
|
444
|
+
# We cannot use ::OpenTelemetry::Trace.with_span here unfortunately. We need to disable the durable
|
|
445
|
+
# scheduler for just the span attach/detach but leave it enabled for the user code (see
|
|
446
|
+
# WorkflowInbound#_attach_current for why we have to disable scheduler even for these simple operations).
|
|
447
|
+
token = Temporalio::Workflow::Unsafe.durable_scheduler_disabled do
|
|
448
|
+
::OpenTelemetry::Context.attach(::OpenTelemetry::Trace.context_with_span(span))
|
|
449
|
+
end
|
|
450
|
+
begin
|
|
409
451
|
# Yield with no parameters
|
|
410
452
|
yield
|
|
453
|
+
ensure
|
|
454
|
+
Temporalio::Workflow::Unsafe.durable_scheduler_disabled do
|
|
455
|
+
::OpenTelemetry::Context.detach(token)
|
|
456
|
+
end
|
|
411
457
|
end
|
|
412
458
|
else
|
|
413
459
|
yield
|
|
@@ -441,25 +487,32 @@ module Temporalio
|
|
|
441
487
|
# Do nothing if replaying and not wanted during replay
|
|
442
488
|
return nil if !even_during_replay && Temporalio::Workflow::Unsafe.replaying?
|
|
443
489
|
|
|
444
|
-
# If there is no span on the context and the user hasn't opted in to always creating, do not create. This
|
|
445
|
-
# prevents orphans if there was no span originally created from the client start-workflow call.
|
|
446
|
-
if ::OpenTelemetry::Trace.current_span == ::OpenTelemetry::Trace::Span::INVALID &&
|
|
447
|
-
!root._always_create_workflow_spans
|
|
448
|
-
return nil
|
|
449
|
-
end
|
|
450
|
-
|
|
451
490
|
# Create attributes, adding user-defined ones
|
|
452
491
|
attributes = { 'temporalWorkflowID' => Temporalio::Workflow.info.workflow_id,
|
|
453
492
|
'temporalRunID' => Temporalio::Workflow.info.run_id }.merge(attributes)
|
|
454
493
|
|
|
455
494
|
time = Temporalio::Workflow.now.dup
|
|
456
495
|
# Disable durable scheduler because 1) synchronous/non-batch span processors in OTel use network (though could
|
|
457
|
-
# have just used
|
|
496
|
+
# have just used Unsafe.io_enabled for this if not for the next point) and 2) OTel uses Ruby Timeout which we
|
|
458
497
|
# don't want to use durable timers.
|
|
459
498
|
Temporalio::Workflow::Unsafe.durable_scheduler_disabled do
|
|
499
|
+
# If there is no span on the context and the user hasn't opted in to always creating, do not create. This
|
|
500
|
+
# prevents orphans if there was no span originally created from the client start-workflow call.
|
|
501
|
+
if ::OpenTelemetry::Trace.current_span == ::OpenTelemetry::Trace::Span::INVALID &&
|
|
502
|
+
!root._always_create_workflow_spans
|
|
503
|
+
return nil
|
|
504
|
+
end
|
|
505
|
+
|
|
460
506
|
span = root.tracer.start_span(name, attributes:, links:, start_timestamp: time, kind:) # steep:ignore
|
|
461
|
-
# Record exception if present
|
|
462
|
-
|
|
507
|
+
# Record exception and set status if present
|
|
508
|
+
if exception
|
|
509
|
+
span.record_exception(exception)
|
|
510
|
+
# Only set the status if it is not a benign application error
|
|
511
|
+
unless exception.is_a?(Error::ApplicationError) &&
|
|
512
|
+
exception.category == Error::ApplicationError::Category::BENIGN
|
|
513
|
+
span.status = ::OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{exception.class}")
|
|
514
|
+
end
|
|
515
|
+
end
|
|
463
516
|
# Finish the span (returns self)
|
|
464
517
|
span.finish(end_timestamp: time)
|
|
465
518
|
end
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'temporalio/internal/bridge'
|
|
5
|
+
|
|
6
|
+
module Temporalio
|
|
7
|
+
# Environment and file-based configuration for Temporal clients
|
|
8
|
+
#
|
|
9
|
+
# WARNING: Experimental API.
|
|
10
|
+
module EnvConfig
|
|
11
|
+
# This module provides utilities to load Temporal client configuration from TOML files
|
|
12
|
+
# and environment variables.
|
|
13
|
+
|
|
14
|
+
# TLS configuration as specified as part of client configuration
|
|
15
|
+
#
|
|
16
|
+
# @!attribute [r] disabled
|
|
17
|
+
# @return [Boolean, nil] If true, TLS is explicitly disabled; if nil, not specified
|
|
18
|
+
# @!attribute [r] server_name
|
|
19
|
+
# @return [String, nil] SNI override
|
|
20
|
+
# @!attribute [r] server_root_ca_cert
|
|
21
|
+
# @return [Pathname, String, nil] Server CA certificate source
|
|
22
|
+
# @!attribute [r] client_cert
|
|
23
|
+
# @return [Pathname, String, nil] Client certificate source
|
|
24
|
+
# @!attribute [r] client_private_key
|
|
25
|
+
# @return [Pathname, String, nil] Client key source
|
|
26
|
+
ClientConfigTLS = Data.define(:disabled, :server_name, :server_root_ca_cert, :client_cert, :client_private_key)
|
|
27
|
+
|
|
28
|
+
# TLS configuration for Temporal client connections.
|
|
29
|
+
#
|
|
30
|
+
# This class provides methods for creating, serializing, and converting
|
|
31
|
+
# TLS configuration objects used by Temporal clients.
|
|
32
|
+
class ClientConfigTLS
|
|
33
|
+
# Create a ClientConfigTLS from a hash
|
|
34
|
+
# @param hash [Hash, nil] Hash representation
|
|
35
|
+
# @return [ClientConfigTLS, nil] The TLS configuration or nil if hash is nil/empty
|
|
36
|
+
def self.from_h(hash)
|
|
37
|
+
return nil if hash.nil? || hash.empty?
|
|
38
|
+
|
|
39
|
+
new(
|
|
40
|
+
disabled: hash[:disabled],
|
|
41
|
+
server_name: hash[:server_name],
|
|
42
|
+
server_root_ca_cert: hash_to_source(hash[:server_ca_cert]),
|
|
43
|
+
client_cert: hash_to_source(hash[:client_cert]),
|
|
44
|
+
client_private_key: hash_to_source(hash[:client_key])
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Set default values
|
|
49
|
+
def initialize(disabled: nil, server_name: nil, server_root_ca_cert: nil, client_cert: nil,
|
|
50
|
+
client_private_key: nil)
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Convert to a hash that can be used for TOML serialization
|
|
55
|
+
# @return [Hash] Dictionary representation
|
|
56
|
+
def to_h
|
|
57
|
+
{
|
|
58
|
+
disabled:,
|
|
59
|
+
server_name:,
|
|
60
|
+
server_ca_cert: server_root_ca_cert ? source_to_hash(server_root_ca_cert) : nil,
|
|
61
|
+
client_cert: client_cert ? source_to_hash(client_cert) : nil,
|
|
62
|
+
client_key: client_private_key ? source_to_hash(client_private_key) : nil
|
|
63
|
+
}.compact
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Create a TLS configuration for use with connections
|
|
67
|
+
# @return [Connection::TLSOptions, false] TLS options or false if disabled
|
|
68
|
+
def to_client_tls_options
|
|
69
|
+
return false if disabled
|
|
70
|
+
|
|
71
|
+
Client::Connection::TLSOptions.new(
|
|
72
|
+
domain: server_name,
|
|
73
|
+
server_root_ca_cert: read_source(server_root_ca_cert),
|
|
74
|
+
client_cert: read_source(client_cert),
|
|
75
|
+
client_private_key: read_source(client_private_key)
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
class << self
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
# Convert hash to source object (Pathname or String)
|
|
85
|
+
def hash_to_source(hash)
|
|
86
|
+
return nil if hash.nil?
|
|
87
|
+
|
|
88
|
+
# Always expect a hash with path or data
|
|
89
|
+
if hash[:path]
|
|
90
|
+
Pathname.new(hash[:path])
|
|
91
|
+
elsif hash[:data]
|
|
92
|
+
hash[:data]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def source_to_hash(source)
|
|
98
|
+
case source
|
|
99
|
+
when Pathname
|
|
100
|
+
{ path: source.to_s }
|
|
101
|
+
when String
|
|
102
|
+
# String is always treated as data content
|
|
103
|
+
{ data: source }
|
|
104
|
+
when nil
|
|
105
|
+
nil
|
|
106
|
+
else
|
|
107
|
+
raise TypeError, "Source must be Pathname, String, or nil, got #{source.class}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def read_source(source)
|
|
112
|
+
case source
|
|
113
|
+
when Pathname
|
|
114
|
+
File.read(source.to_s)
|
|
115
|
+
when String
|
|
116
|
+
# String is always treated as raw data content
|
|
117
|
+
source
|
|
118
|
+
when nil
|
|
119
|
+
nil
|
|
120
|
+
else
|
|
121
|
+
raise TypeError, "Source must be Pathname, String, or nil, got #{source.class}"
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Represents a client configuration profile.
|
|
127
|
+
#
|
|
128
|
+
# This class holds the configuration as loaded from a file or environment.
|
|
129
|
+
# See #to_client_connect_options to transform the profile to a connect config hash.
|
|
130
|
+
#
|
|
131
|
+
# @!attribute [r] address
|
|
132
|
+
# @return [String, nil] Client address
|
|
133
|
+
# @!attribute [r] namespace
|
|
134
|
+
# @return [String, nil] Client namespace
|
|
135
|
+
# @!attribute [r] api_key
|
|
136
|
+
# @return [String, nil] Client API key
|
|
137
|
+
# @!attribute [r] tls
|
|
138
|
+
# @return [Boolean, ClientConfigTLS, nil] TLS configuration
|
|
139
|
+
# @!attribute [r] grpc_meta
|
|
140
|
+
# @return [Hash] gRPC metadata
|
|
141
|
+
ClientConfigProfile = Data.define(:address, :namespace, :api_key, :tls, :grpc_meta)
|
|
142
|
+
|
|
143
|
+
# A client configuration profile loaded from environment and files.
|
|
144
|
+
#
|
|
145
|
+
# This class represents a complete client configuration profile that can be
|
|
146
|
+
# loaded from TOML files and environment variables, and converted to client
|
|
147
|
+
# connection options.
|
|
148
|
+
class ClientConfigProfile
|
|
149
|
+
# Create a ClientConfigProfile from a hash
|
|
150
|
+
# @param hash [Hash] Hash representation
|
|
151
|
+
# @return [ClientConfigProfile] The client profile
|
|
152
|
+
def self.from_h(hash)
|
|
153
|
+
new(
|
|
154
|
+
address: hash[:address],
|
|
155
|
+
namespace: hash[:namespace],
|
|
156
|
+
api_key: hash[:api_key],
|
|
157
|
+
tls: ClientConfigTLS.from_h(hash[:tls]),
|
|
158
|
+
grpc_meta: hash[:grpc_meta] || {}
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Load a single client profile from given sources, applying env overrides.
|
|
163
|
+
#
|
|
164
|
+
# @param profile [String, nil] Profile to load from the config
|
|
165
|
+
# @param config_source [Pathname, String, nil] Configuration source -
|
|
166
|
+
# Pathname for file path, String for TOML content
|
|
167
|
+
# @param disable_file [Boolean] If true, file loading is disabled
|
|
168
|
+
# @param disable_env [Boolean] If true, environment variable loading and overriding is disabled
|
|
169
|
+
# @param config_file_strict [Boolean] If true, will error on unrecognized keys
|
|
170
|
+
# @param override_env_vars [Hash, nil] Environment variables to use for loading and overrides
|
|
171
|
+
# @return [ClientConfigProfile] The client configuration profile
|
|
172
|
+
def self.load(
|
|
173
|
+
profile: nil,
|
|
174
|
+
config_source: nil,
|
|
175
|
+
disable_file: false,
|
|
176
|
+
disable_env: false,
|
|
177
|
+
config_file_strict: false,
|
|
178
|
+
override_env_vars: nil
|
|
179
|
+
)
|
|
180
|
+
path, data = EnvConfig._source_to_path_and_data(config_source)
|
|
181
|
+
|
|
182
|
+
raw_profile = Internal::Bridge::EnvConfig.load_client_connect_config(
|
|
183
|
+
profile,
|
|
184
|
+
path,
|
|
185
|
+
data,
|
|
186
|
+
disable_file,
|
|
187
|
+
disable_env,
|
|
188
|
+
config_file_strict,
|
|
189
|
+
override_env_vars || {}
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
from_h(raw_profile)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Create a ClientConfigProfile instance with defaults
|
|
196
|
+
def initialize(address: nil, namespace: nil, api_key: nil, tls: nil, grpc_meta: {})
|
|
197
|
+
super
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Convert to a hash that can be used for TOML serialization
|
|
201
|
+
# @return [Hash] Dictionary representation
|
|
202
|
+
def to_h
|
|
203
|
+
{
|
|
204
|
+
address: address,
|
|
205
|
+
namespace: namespace,
|
|
206
|
+
api_key: api_key,
|
|
207
|
+
tls: tls&.to_h&.then { |tls_hash| tls_hash.empty? ? nil : tls_hash }, # steep:ignore
|
|
208
|
+
grpc_meta: grpc_meta && grpc_meta.empty? ? nil : grpc_meta
|
|
209
|
+
}.compact
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Create a client connect config from this profile
|
|
213
|
+
# @return [Array] Tuple of [positional_args, keyword_args] that can be splatted to Client.connect
|
|
214
|
+
def to_client_connect_options
|
|
215
|
+
positional_args = [address, namespace]
|
|
216
|
+
tls_value = false
|
|
217
|
+
if tls
|
|
218
|
+
tls_value = tls.to_client_tls_options
|
|
219
|
+
elsif api_key
|
|
220
|
+
tls_value = true
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
keyword_args = {
|
|
224
|
+
api_key: api_key,
|
|
225
|
+
rpc_metadata: (grpc_meta if grpc_meta && !grpc_meta.empty?),
|
|
226
|
+
tls: tls_value
|
|
227
|
+
}.compact
|
|
228
|
+
|
|
229
|
+
[positional_args, keyword_args]
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Client configuration loaded from TOML and environment variables.
|
|
234
|
+
#
|
|
235
|
+
# This contains a mapping of profile names to client profiles.
|
|
236
|
+
#
|
|
237
|
+
# @!attribute [r] profiles
|
|
238
|
+
# @return [Hash<String, ClientConfigProfile>] Map of profile name to its corresponding ClientConfigProfile
|
|
239
|
+
ClientConfig = Data.define(:profiles)
|
|
240
|
+
|
|
241
|
+
# Container for multiple client configuration profiles.
|
|
242
|
+
#
|
|
243
|
+
# This class holds a collection of named client profiles loaded from
|
|
244
|
+
# configuration sources and provides methods for profile management
|
|
245
|
+
# and client connection configuration.
|
|
246
|
+
class ClientConfig
|
|
247
|
+
# Create a ClientConfig from a hash
|
|
248
|
+
# @param hash [Hash] Hash representation
|
|
249
|
+
# @return [ClientConfig] The client configuration
|
|
250
|
+
def self.from_h(hash)
|
|
251
|
+
profiles = hash.transform_values do |profile_hash|
|
|
252
|
+
ClientConfigProfile.from_h(profile_hash)
|
|
253
|
+
end
|
|
254
|
+
new(profiles: profiles)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Load all client profiles from given sources.
|
|
258
|
+
#
|
|
259
|
+
# This does not apply environment variable overrides to the profiles, it
|
|
260
|
+
# only uses an environment variable to find the default config file path
|
|
261
|
+
# (TEMPORAL_CONFIG_FILE).
|
|
262
|
+
#
|
|
263
|
+
# @param config_source [Pathname, String, nil] Configuration source
|
|
264
|
+
# @param config_file_strict [Boolean] If true, will error on unrecognized keys
|
|
265
|
+
# @param override_env_vars [Hash, nil] Environment variables to use
|
|
266
|
+
# @return [ClientConfig] The client configuration
|
|
267
|
+
def self.load(
|
|
268
|
+
config_source: nil,
|
|
269
|
+
config_file_strict: false,
|
|
270
|
+
override_env_vars: nil
|
|
271
|
+
)
|
|
272
|
+
path, data = EnvConfig._source_to_path_and_data(config_source)
|
|
273
|
+
|
|
274
|
+
loaded_profiles = Internal::Bridge::EnvConfig.load_client_config(
|
|
275
|
+
path,
|
|
276
|
+
data,
|
|
277
|
+
config_file_strict,
|
|
278
|
+
override_env_vars || {}
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
from_h(loaded_profiles)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Load a single client profile and convert to connect config
|
|
285
|
+
#
|
|
286
|
+
# This is a convenience function that combines loading a profile and
|
|
287
|
+
# converting it to a connect config hash.
|
|
288
|
+
#
|
|
289
|
+
# @param profile [String, nil] The profile to load from the config
|
|
290
|
+
# @param config_source [Pathname, String, nil] Configuration source
|
|
291
|
+
# @param disable_file [Boolean] If true, file loading is disabled
|
|
292
|
+
# @param disable_env [Boolean] If true, environment variable loading and overriding is disabled
|
|
293
|
+
# @param config_file_strict [Boolean] If true, will error on unrecognized keys
|
|
294
|
+
# @param override_env_vars [Hash, nil] Environment variables to use for loading and overrides
|
|
295
|
+
# @return [Array] Tuple of [positional_args, keyword_args] that can be splatted to Client.connect
|
|
296
|
+
def self.load_client_connect_options(
|
|
297
|
+
profile: nil,
|
|
298
|
+
config_source: nil,
|
|
299
|
+
disable_file: false,
|
|
300
|
+
disable_env: false,
|
|
301
|
+
config_file_strict: false,
|
|
302
|
+
override_env_vars: nil
|
|
303
|
+
)
|
|
304
|
+
prof = ClientConfigProfile.load(
|
|
305
|
+
profile: profile,
|
|
306
|
+
config_source: config_source,
|
|
307
|
+
disable_file: disable_file,
|
|
308
|
+
disable_env: disable_env,
|
|
309
|
+
config_file_strict: config_file_strict,
|
|
310
|
+
override_env_vars: override_env_vars
|
|
311
|
+
)
|
|
312
|
+
prof.to_client_connect_options
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Create a ClientConfig instance with defaults
|
|
316
|
+
def initialize(profiles: {})
|
|
317
|
+
super
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# Convert to a hash that can be used for TOML serialization
|
|
321
|
+
# @return [Hash] Dictionary representation
|
|
322
|
+
def to_h
|
|
323
|
+
profiles.transform_values(&:to_h)
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# @param source [Pathname, String, nil] Configuration source
|
|
328
|
+
# @return [Array<String?, String?>] Tuple of [path, data]
|
|
329
|
+
# @!visibility private
|
|
330
|
+
def self._source_to_path_and_data(source)
|
|
331
|
+
case source
|
|
332
|
+
when Pathname
|
|
333
|
+
[source.to_s, nil]
|
|
334
|
+
when String
|
|
335
|
+
[nil, source]
|
|
336
|
+
when nil
|
|
337
|
+
[nil, nil]
|
|
338
|
+
else
|
|
339
|
+
raise TypeError, "Must be Pathname, String, or nil, got #{source.class}"
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
end
|
data/lib/temporalio/error.rb
CHANGED
|
@@ -97,9 +97,13 @@ module Temporalio
|
|
|
97
97
|
|
|
98
98
|
# Error that occurs when an async activity handle tries to heartbeat and the activity is marked as canceled.
|
|
99
99
|
class AsyncActivityCanceledError < Error
|
|
100
|
+
# @return [Activity::CancellationDetails]
|
|
101
|
+
attr_reader :details
|
|
102
|
+
|
|
100
103
|
# @!visibility private
|
|
101
|
-
def initialize
|
|
104
|
+
def initialize(details)
|
|
102
105
|
super('Activity canceled')
|
|
106
|
+
@details = details
|
|
103
107
|
end
|
|
104
108
|
end
|
|
105
109
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|