Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion temporalio/ext/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ use std::{collections::HashMap, future::Future, marker::PhantomData, time::Durat

use temporalio_client::{
ClientKeepAliveOptions, ClientTlsOptions, Connection, ConnectionOptions,
HttpConnectProxyOptions, RetryOptions, TlsOptions, errors::ClientConnectError,
DnsLoadBalancingOptions, HttpConnectProxyOptions, RetryOptions, TlsOptions,
errors::ClientConnectError,
};

use magnus::{
DataTypeFunctions, Error, RHash, RString, Ruby, TypedData, Value, function, method, prelude::*,
scan_args,
};
use tonic::{Status, metadata::MetadataKey};
use tracing::warn;
use url::Url;

use super::{ROOT_MOD, error, id, new_error};
Expand Down Expand Up @@ -181,6 +183,17 @@ impl Client {
None
},
)
.dns_load_balancing(if options.child(id!("http_connect_proxy"))?.is_some() {
warn!("Disabling DNS load balancing because http_connect_proxy is set");
None
} else if let Some(dns) = options.child(id!("dns_load_balancing"))? {
let mut opts = DnsLoadBalancingOptions::default();
opts.resolution_interval =
Duration::from_secs_f64(dns.member(id!("resolution_interval"))?);
Some(opts)
} else {
None
})
.maybe_metrics_meter(metrics_meter)
.build();

Expand Down
7 changes: 6 additions & 1 deletion temporalio/lib/temporalio/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ class ListWorkflowPage; end # rubocop:disable Lint/EmptyClass
# @param runtime [Runtime] Runtime for this client.
# @param lazy_connect [Boolean] If true, the client will not connect until the first call is attempted or a worker
# is created with it. Lazy clients cannot be used for workers if they have not performed a connection.
# @param dns_load_balancing [Connection::DnsLoadBalancingOptions, nil] DNS load balancing options for the
# connection. Default is +nil+ (disabled). Silently disabled when +http_connect_proxy+ is set, since the two are
# mutually exclusive.
#
# @return [Client] Connected client.
#
Expand All @@ -116,7 +119,8 @@ def self.connect(
keep_alive: Connection::KeepAliveOptions.new, # Set to nil to disable
http_connect_proxy: nil,
runtime: Runtime.default,
lazy_connect: false
lazy_connect: false,
dns_load_balancing: nil
)
# Prepare connection. The connection var is needed here so it can be used in callback for plugin.
base_connection = nil
Expand Down Expand Up @@ -162,6 +166,7 @@ def self.connect(
http_connect_proxy:,
runtime:,
lazy_connect:,
dns_load_balancing:,
around_connect: # steep:ignore
)

Expand Down
30 changes: 28 additions & 2 deletions temporalio/lib/temporalio/client/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class Connection
:keep_alive,
:http_connect_proxy,
:runtime,
:lazy_connect
:lazy_connect,
:dns_load_balancing
)

# Options as returned from {options} for +**to_h+ splat use in {initialize}. See {initialize} for details.
Expand Down Expand Up @@ -132,6 +133,22 @@ def initialize(interval: 30.0, timeout: 15.0)
# @return [String, nil] Pass for HTTP basic auth for the proxy, must be combined with {basic_auth_user}.
class HTTPConnectProxyOptions; end # rubocop:disable Lint/EmptyClass

DnsLoadBalancingOptions = Data.define(
:resolution_interval
)

# DNS load balancing options for client connections. When set, Core periodically re-resolves the target host's
# DNS records and round-robins requests across the resolved addresses. Mutually exclusive with
# {HTTPConnectProxyOptions} -- DNS load balancing is silently disabled when an HTTP CONNECT proxy is configured.
#
# @!attribute resolution_interval
# @return [Float] How often to re-resolve DNS, in seconds. Default 30.0.
class DnsLoadBalancingOptions
def initialize(resolution_interval: 30.0)
super
end
end

# @return [Options] Frozen options for this client which has the same attributes as {initialize}. Note that if
# {api_key=} or {rpc_metadata=} are updated, the options object is replaced with those changes (it is not
# mutated in place).
Expand Down Expand Up @@ -169,6 +186,8 @@ class HTTPConnectProxyOptions; end # rubocop:disable Lint/EmptyClass
# @param lazy_connect [Boolean] If true, there is no connection until the first call is attempted or a worker
# is created with it. Clients from lazy connections cannot be used for workers if they have not performed a
# connection.
# @param dns_load_balancing [DnsLoadBalancingOptions, nil] DNS load balancing options for this connection. Default
# is +nil+ (disabled). Silently disabled when +http_connect_proxy+ is set, since the two are mutually exclusive.
# @param around_connect [Proc, nil] If present, this proc accepts two values: options and a block. The block must
# be yielded to only once with the options. The block does not return a meaningful value, nor should
# around_connect.
Expand All @@ -185,6 +204,7 @@ def initialize(
http_connect_proxy: nil,
runtime: Runtime.default,
lazy_connect: false,
dns_load_balancing: nil,
around_connect: nil
)
@options = Options.new(
Expand All @@ -197,7 +217,8 @@ def initialize(
keep_alive:,
http_connect_proxy:,
runtime:,
lazy_connect:
lazy_connect:,
dns_load_balancing:
).freeze
@core_client_mutex = Mutex.new
# Create core client now if not lazy, applying around_connect if present
Expand Down Expand Up @@ -329,6 +350,11 @@ def new_core_client
basic_auth_pass: @options.http_connect_proxy.basic_auth_pass
)
end
if (dns_load_balancing = @options.dns_load_balancing)
options.dns_load_balancing = Internal::Bridge::Client::DnsLoadBalancingOptions.new(
resolution_interval: dns_load_balancing.resolution_interval
)
end
Internal::Bridge::Client.new(@options.runtime._core_runtime, options)
end
end
Expand Down
7 changes: 6 additions & 1 deletion temporalio/lib/temporalio/internal/bridge/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class Client
:tls, # Optional
:rpc_retry,
:keep_alive, # Optional
:http_connect_proxy # Optional
:http_connect_proxy, # Optional
:dns_load_balancing # Optional
)

TLSOptions = Struct.new(
Expand Down Expand Up @@ -46,6 +47,10 @@ class Client
:basic_auth_pass # Optional
)

DnsLoadBalancingOptions = Struct.new(
:resolution_interval
)

def self.new(runtime, options)
queue = Queue.new
async_new(runtime, options, queue)
Expand Down
3 changes: 2 additions & 1 deletion temporalio/sig/temporalio/client.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ module Temporalio
?keep_alive: Connection::KeepAliveOptions,
?http_connect_proxy: Connection::HTTPConnectProxyOptions?,
?runtime: Runtime,
?lazy_connect: bool
?lazy_connect: bool,
?dns_load_balancing: Connection::DnsLoadBalancingOptions?
) -> Client

def self._validate_plugins!: (Array[Plugin] plugins) -> void
Expand Down
13 changes: 12 additions & 1 deletion temporalio/sig/temporalio/client/connection.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module Temporalio
attr_reader http_connect_proxy: HTTPConnectProxyOptions
attr_reader runtime: Runtime
attr_reader lazy_connect: bool
attr_reader dns_load_balancing: DnsLoadBalancingOptions?

def initialize: (
target_host: String,
Expand All @@ -23,7 +24,8 @@ module Temporalio
keep_alive: KeepAliveOptions,
http_connect_proxy: HTTPConnectProxyOptions?,
runtime: Runtime,
lazy_connect: bool
lazy_connect: bool,
dns_load_balancing: DnsLoadBalancingOptions?
) -> void

def to_h: -> Hash[Symbol, untyped]
Expand Down Expand Up @@ -85,6 +87,14 @@ module Temporalio
) -> void
end

class DnsLoadBalancingOptions
attr_reader resolution_interval: Float

def initialize: (
?resolution_interval: Float
) -> void
end

attr_reader options: Options

# TODO(cretz): Update when generated
Expand All @@ -106,6 +116,7 @@ module Temporalio
?http_connect_proxy: HTTPConnectProxyOptions?,
?runtime: Runtime,
?lazy_connect: bool,
?dns_load_balancing: DnsLoadBalancingOptions?,
?around_connect: nil | ^(Options) { (Options) -> void } -> void
) -> void

Expand Down
16 changes: 13 additions & 3 deletions temporalio/sig/temporalio/internal/bridge/client.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ module Temporalio
attr_accessor rpc_retry: RPCRetryOptions
attr_accessor keep_alive: KeepAliveOptions?
attr_accessor http_connect_proxy: HTTPConnectProxyOptions?

attr_accessor dns_load_balancing: DnsLoadBalancingOptions?

def initialize: (
target_host: String,
client_name: String,
Expand All @@ -24,7 +25,8 @@ module Temporalio
?tls: TLSOptions?,
rpc_retry: RPCRetryOptions,
?keep_alive: KeepAliveOptions?,
?http_connect_proxy: HTTPConnectProxyOptions?
?http_connect_proxy: HTTPConnectProxyOptions?,
?dns_load_balancing: DnsLoadBalancingOptions?
) -> void
end

Expand Down Expand Up @@ -74,14 +76,22 @@ module Temporalio
attr_accessor target_host: String
attr_accessor basic_auth_user: String?
attr_accessor basic_auth_pass: String?

def initialize: (
target_host: String,
basic_auth_user: String?,
basic_auth_pass: String?
) -> void
end

class DnsLoadBalancingOptions
attr_accessor resolution_interval: Float

def initialize: (
resolution_interval: Float
) -> void
end

# Defined in Rust

SERVICE_WORKFLOW: Integer
Expand Down
22 changes: 22 additions & 0 deletions temporalio/test/client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ def test_lazy_connection
assert client.connection.connected?
end

def test_dns_load_balancing_default_nil
client = Temporalio::Client.connect('localhost:7233', 'default', lazy_connect: true)
assert_nil client.connection.options.dns_load_balancing
end

def test_dns_load_balancing_custom_preserved
dns_opts = Temporalio::Client::Connection::DnsLoadBalancingOptions.new(resolution_interval: 5.0)
client = Temporalio::Client.connect(
'localhost:7233', 'default', lazy_connect: true, dns_load_balancing: dns_opts
)
stored = client.connection.options.dns_load_balancing
assert_equal dns_opts, stored
raise 'stored is nil' if stored.nil?

assert_in_delta 5.0, stored.resolution_interval
end

def test_dns_load_balancing_default_interval
opts = Temporalio::Client::Connection::DnsLoadBalancingOptions.new
assert_in_delta 30.0, opts.resolution_interval
end

class TrackCallsInterceptor
include Temporalio::Client::Interceptor

Expand Down
Loading