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
14 changes: 14 additions & 0 deletions crates/sdk-core-c-bridge/include/temporal-sdk-core-c-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ typedef struct TemporalCoreClientHttpConnectProxyOptions {
typedef void (*TemporalCoreClientGrpcOverrideCallback)(struct TemporalCoreClientGrpcOverrideRequest *request,
void *user_data);

typedef struct TemporalCoreClientDnsLoadBalancingOptions {
/**
* How often, in milliseconds, to re-resolve DNS.
*/
uint64_t resolution_interval_millis;
} TemporalCoreClientDnsLoadBalancingOptions;

typedef struct TemporalCoreConnectionOptions {
struct TemporalCoreByteArrayRef target_url;
struct TemporalCoreByteArrayRef client_name;
Expand Down Expand Up @@ -172,6 +179,13 @@ typedef struct TemporalCoreConnectionOptions {
* Optional user data passed to each callback call.
*/
void *grpc_override_callback_user_data;
/**
* If non-null, DNS-based load balancing is enabled. When the target URL resolves to multiple
* addresses, requests are distributed across them and the address list is periodically
* refreshed. If null, DNS load balancing is disabled. Ignored (forced off) when
* http_connect_proxy_options is also set.
*/
const struct TemporalCoreClientDnsLoadBalancingOptions *dns_load_balancing_options;
} TemporalCoreConnectionOptions;

typedef struct TemporalCoreByteArray {
Expand Down
109 changes: 103 additions & 6 deletions crates/sdk-core-c-bridge/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ pub struct ConnectionOptions {
pub grpc_override_callback: ClientGrpcOverrideCallback,
/// Optional user data passed to each callback call.
pub grpc_override_callback_user_data: *mut libc::c_void,
/// If non-null, DNS-based load balancing is enabled. When the target URL resolves to multiple
/// addresses, requests are distributed across them and the address list is periodically
/// refreshed. If null, DNS load balancing is disabled. Ignored (forced off) when
/// http_connect_proxy_options is also set.
pub dns_load_balancing_options: *const ClientDnsLoadBalancingOptions,
}

#[repr(C)]
Expand Down Expand Up @@ -78,6 +83,12 @@ pub struct ClientHttpConnectProxyOptions {
pub password: ByteArrayRef,
}

#[repr(C)]
pub struct ClientDnsLoadBalancingOptions {
/// How often, in milliseconds, to re-resolve DNS.
pub resolution_interval_millis: u64,
}

type CoreConnection = temporalio_client::Connection;

pub struct Connection {
Expand Down Expand Up @@ -1362,6 +1373,20 @@ impl TryFrom<&ConnectionOptions> for temporalio_client::ConnectionOptions {
let http_connect_proxy =
unsafe { opts.http_connect_proxy_options.as_ref() }.map(Into::into);

let dns_load_balancing =
unsafe { opts.dns_load_balancing_options.as_ref() }.map(Into::into);
let dns_load_balancing: Option<temporalio_client::DnsLoadBalancingOptions> =
if http_connect_proxy.is_some() {
if dns_load_balancing.is_some() {
tracing::warn!(
"Disabling DNS load balancing because http_connect_proxy_options is set"
);
}
None
} else {
dns_load_balancing
};

Ok(
temporalio_client::ConnectionOptions::new(Url::parse(opts.target_url.to_str())?)
.client_name(opts.client_name.to_string())
Expand All @@ -1375,12 +1400,8 @@ impl TryFrom<&ConnectionOptions> for temporalio_client::ConnectionOptions {
.maybe_headers(headers)
.maybe_binary_headers(binary_headers)
.maybe_api_key(api_key)
.maybe_http_connect_proxy(http_connect_proxy.clone())
.dns_load_balancing(if http_connect_proxy.is_some() {
None
} else {
Some(temporalio_client::DnsLoadBalancingOptions::default())
})
.maybe_http_connect_proxy(http_connect_proxy)
.dns_load_balancing(dns_load_balancing)
.maybe_tls_options(tls_cfg)
.build(),
)
Expand Down Expand Up @@ -1441,6 +1462,14 @@ impl From<&ClientKeepAliveOptions> for temporalio_client::ClientKeepAliveOptions
}
}

impl From<&ClientDnsLoadBalancingOptions> for temporalio_client::DnsLoadBalancingOptions {
fn from(opts: &ClientDnsLoadBalancingOptions) -> Self {
let mut out = temporalio_client::DnsLoadBalancingOptions::default();
out.resolution_interval = Duration::from_millis(opts.resolution_interval_millis);
out
}
}

impl From<&ClientHttpConnectProxyOptions> for temporalio_client::proxy::HttpConnectProxyOptions {
fn from(opts: &ClientHttpConnectProxyOptions) -> Self {
temporalio_client::proxy::HttpConnectProxyOptions {
Expand All @@ -1462,3 +1491,71 @@ impl From<&GrpcMetadataHolder> for MetadataRef {
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::ByteArrayRefArray;

fn base_connection_options() -> ConnectionOptions {
ConnectionOptions {
target_url: "http://localhost:7233".into(),
client_name: ByteArrayRef::empty(),
client_version: ByteArrayRef::empty(),
metadata: ByteArrayRefArray::empty(),
binary_metadata: ByteArrayRefArray::empty(),
api_key: ByteArrayRef::empty(),
identity: ByteArrayRef::empty(),
tls_options: std::ptr::null(),
retry_options: std::ptr::null(),
keep_alive_options: std::ptr::null(),
http_connect_proxy_options: std::ptr::null(),
grpc_override_callback: None,
grpc_override_callback_user_data: std::ptr::null_mut(),
dns_load_balancing_options: std::ptr::null(),
}
}

#[test]
fn dns_load_balancing_null_pointer_disables() {
let opts = base_connection_options();
let converted: temporalio_client::ConnectionOptions = (&opts).try_into().unwrap();
assert!(converted.dns_load_balancing.is_none());
}

#[test]
fn dns_load_balancing_non_zero_interval_passes_through() {
let dns = ClientDnsLoadBalancingOptions {
resolution_interval_millis: 5_000,
};
let opts = ConnectionOptions {
dns_load_balancing_options: &dns,
..base_connection_options()
};
let converted: temporalio_client::ConnectionOptions = (&opts).try_into().unwrap();
let dns_opts = converted
.dns_load_balancing
.expect("DNS load balancing should be enabled");
assert_eq!(dns_opts.resolution_interval, Duration::from_millis(5_000));
}

#[test]
fn dns_load_balancing_silently_disabled_when_http_proxy_set() {
let dns = ClientDnsLoadBalancingOptions {
resolution_interval_millis: 5_000,
};
let proxy = ClientHttpConnectProxyOptions {
target_host: "proxy.example.com:8080".into(),
username: ByteArrayRef::empty(),
password: ByteArrayRef::empty(),
};
let opts = ConnectionOptions {
dns_load_balancing_options: &dns,
http_connect_proxy_options: &proxy,
..base_connection_options()
};
let converted: temporalio_client::ConnectionOptions = (&opts).try_into().unwrap();
assert!(converted.dns_load_balancing.is_none());
assert!(converted.http_connect_proxy.is_some());
}
}
12 changes: 10 additions & 2 deletions crates/sdk-core-c-bridge/src/tests/context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
client::{
ClientHttpConnectProxyOptions, ClientKeepAliveOptions, ClientRetryOptions,
ClientTlsOptions, Connection, GrpcMetadataHolder, RpcCallOptions,
ClientDnsLoadBalancingOptions, ClientHttpConnectProxyOptions, ClientKeepAliveOptions,
ClientRetryOptions, ClientTlsOptions, Connection, GrpcMetadataHolder, RpcCallOptions,
temporal_core_client_connect, temporal_core_client_free, temporal_core_client_rpc_call,
},
runtime::{
Expand Down Expand Up @@ -340,6 +340,12 @@ impl Context {
})
});

let dns_load_balancing_options = options.dns_load_balancing.as_ref().map(|dns| {
Box::new(ClientDnsLoadBalancingOptions {
resolution_interval_millis: dns.resolution_interval.as_millis() as u64,
})
});

let client_options = Box::new(crate::client::ConnectionOptions {
target_url: options.target.as_str().into(),
client_name: options.get_client_name().into(),
Expand All @@ -352,6 +358,7 @@ impl Context {
retry_options: &*retry_options,
keep_alive_options: pointer_or_null(keep_alive_options.as_deref()),
http_connect_proxy_options: pointer_or_null(proxy_options.as_deref()),
dns_load_balancing_options: pointer_or_null(dns_load_balancing_options.as_deref()),
grpc_override_callback,
grpc_override_callback_user_data,
});
Expand All @@ -368,6 +375,7 @@ impl Context {
retry_options,
keep_alive_options,
proxy_options,
dns_load_balancing_options,
client_options,
)),
})) as *mut libc::c_void;
Expand Down
Loading