Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
dd91bde
envconfig impl
THardy98 Aug 23, 2025
3504fad
linting
THardy98 Aug 25, 2025
4d79036
fix steep type checks
THardy98 Aug 25, 2025
e89c4ab
Merge branch 'main' into env_config
THardy98 Aug 25, 2025
a79438c
formatting
THardy98 Aug 25, 2025
6dfaca3
Refactor envconfig classes to use Data.define for immutability
THardy98 Sep 5, 2025
3fb3b51
Rename hash methods to use idiomatic Ruby naming
THardy98 Sep 5, 2025
12d3824
Replace TLS config hash with Connection::TLSOptions object
THardy98 Sep 8, 2025
a3696a0
Refactor to use inline pattern instead of temporary variables
THardy98 Sep 8, 2025
027a1ba
Refactor to_client_connect_options to return tuple for one-liner usage
THardy98 Sep 8, 2025
902dbfe
Make hash methods private
THardy98 Sep 9, 2025
4979a3d
Remove File.exist? check by using type system for path vs data distin…
THardy98 Sep 9, 2025
33eccab
Use symbol keys instead of string keys in Rust FFI bridge
THardy98 Sep 9, 2025
1ded95f
Bump golang.org/x/net in /temporalio/test/golangworker (#303)
dependabot[bot] Sep 3, 2025
0d16b46
Bump tracing-subscriber from 0.3.19 to 0.3.20 in /temporalio (#331)
dependabot[bot] Sep 3, 2025
5c49d24
Reduce the scope of the illegal call tracer and other tracing fixes (…
cretz Sep 8, 2025
b0b337e
Remove unnecessary fully qualified import names
THardy98 Sep 9, 2025
928070c
Remove envconfig import in temporalio.rb
THardy98 Sep 9, 2025
fae411e
_source_to_path_and_data prefixed with underscore and private doc vis…
THardy98 Sep 9, 2025
35c2f47
TLS disabled field now optional
THardy98 Sep 9, 2025
5af7ceb
Rubocop fixes
THardy98 Sep 9, 2025
7f2f777
Steep fixes
THardy98 Sep 9, 2025
4a276af
Renamed envconfig.rb -> env_config.rb
THardy98 Sep 9, 2025
6fe479e
Pass data string as RString, Rust bridge converts to Vec
THardy98 Sep 9, 2025
20f28ff
Rename load_client_connect_config -> load_client_connect_options
THardy98 Sep 9, 2025
dee3b0a
Format envconfig.rs
THardy98 Sep 9, 2025
f3b478f
Merge branch 'main' into env_config
THardy98 Sep 9, 2025
656a511
Nits
THardy98 Sep 9, 2025
cde7c6f
Update core submodule
THardy98 Sep 9, 2025
89e03de
Revert irrelevant cancellation changes
THardy98 Sep 9, 2025
aeaf17a
Update Cargo.lock
THardy98 Sep 9, 2025
6db2dcc
Propagate set_headers failure in client bridge
THardy98 Sep 10, 2025
edfed08
Add experimental warning
THardy98 Sep 10, 2025
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
402 changes: 162 additions & 240 deletions temporalio/Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion temporalio/ext/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ prost = "0.13"
rb-sys = "0.9"
temporal-client = { version = "0.1.0", path = "./sdk-core/client" }
temporal-sdk-core = { version = "0.1.0", path = "./sdk-core/core", features = ["ephemeral-server"] }
temporal-sdk-core-api = { version = "0.1.0", path = "./sdk-core/core-api" }
temporal-sdk-core-api = { version = "0.1.0", path = "./sdk-core/core-api", features = ["envconfig"] }
temporal-sdk-core-protos = { version = "0.1.0", path = "./sdk-core/sdk-core-protos" }
tokio = "1.37"
tokio-stream = "0.1"
Expand Down
2 changes: 1 addition & 1 deletion temporalio/ext/sdk-core
Submodule sdk-core updated 115 files
7 changes: 5 additions & 2 deletions temporalio/ext/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,11 @@ impl Client {
self.invoke_rpc(service, callback, call)
}

pub fn update_metadata(&self, headers: HashMap<String, String>) {
self.core.get_client().set_headers(headers);
pub fn update_metadata(&self, headers: HashMap<String, String>) -> Result<(), Error> {
self.core
.get_client()
.set_headers(headers)
.map_err(|err| error!("Invalid headers: {}", err))
}

pub fn update_api_key(&self, api_key: Option<String>) {
Expand Down
241 changes: 241 additions & 0 deletions temporalio/ext/src/envconfig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
use std::collections::HashMap;

use magnus::{Error, RHash, RString, Ruby, class, function, prelude::*, scan_args};
use temporal_sdk_core_api::envconfig::{
ClientConfig as CoreClientConfig, ClientConfigCodec,
ClientConfigProfile as CoreClientConfigProfile, ClientConfigTLS as CoreClientConfigTLS,
DataSource, LoadClientConfigOptions, LoadClientConfigProfileOptions,
load_client_config as core_load_client_config,
load_client_config_profile as core_load_client_config_profile,
};

use crate::{ROOT_MOD, error};

pub fn init(ruby: &Ruby) -> Result<(), Error> {
let root_mod = ruby.get_inner(&ROOT_MOD);

let class = root_mod.define_class("EnvConfig", class::object())?;
class.define_singleton_method("load_client_config", function!(load_client_config, -1))?;
class.define_singleton_method(
"load_client_connect_config",
function!(load_client_connect_config, -1),
)?;

Ok(())
}

fn data_source_to_hash(ruby: &Ruby, ds: &DataSource) -> Result<RHash, Error> {
let hash = RHash::new();
match ds {
DataSource::Path(p) => {
hash.aset(ruby.sym_new("path"), ruby.str_new(p))?;
}
DataSource::Data(d) => {
hash.aset(ruby.sym_new("data"), ruby.str_from_slice(d))?;
}
}
Ok(hash)
}

fn tls_to_hash(ruby: &Ruby, tls: &CoreClientConfigTLS) -> Result<RHash, Error> {
let hash = RHash::new();
hash.aset(ruby.sym_new("disabled"), tls.disabled)?;

if let Some(v) = &tls.client_cert {
hash.aset(ruby.sym_new("client_cert"), data_source_to_hash(ruby, v)?)?;
}
if let Some(v) = &tls.client_key {
hash.aset(ruby.sym_new("client_key"), data_source_to_hash(ruby, v)?)?;
}
if let Some(v) = &tls.server_ca_cert {
hash.aset(
ruby.sym_new("server_ca_cert"),
data_source_to_hash(ruby, v)?,
)?;
}
if let Some(v) = &tls.server_name {
hash.aset(ruby.sym_new("server_name"), ruby.str_new(v))?;
}
hash.aset(
ruby.sym_new("disable_host_verification"),
tls.disable_host_verification,
)?;

Ok(hash)
}

fn codec_to_hash(ruby: &Ruby, codec: &ClientConfigCodec) -> Result<RHash, Error> {
let hash = RHash::new();
if let Some(v) = &codec.endpoint {
hash.aset(ruby.sym_new("endpoint"), ruby.str_new(v))?;
}
if let Some(v) = &codec.auth {
hash.aset(ruby.sym_new("auth"), ruby.str_new(v))?;
}
Ok(hash)
}

fn profile_to_hash(ruby: &Ruby, profile: &CoreClientConfigProfile) -> Result<RHash, Error> {
let hash = RHash::new();

if let Some(v) = &profile.address {
hash.aset(ruby.sym_new("address"), ruby.str_new(v))?;
}
if let Some(v) = &profile.namespace {
hash.aset(ruby.sym_new("namespace"), ruby.str_new(v))?;
}
if let Some(v) = &profile.api_key {
hash.aset(ruby.sym_new("api_key"), ruby.str_new(v))?;
}
if let Some(tls) = &profile.tls {
hash.aset(ruby.sym_new("tls"), tls_to_hash(ruby, tls)?)?;
}
if let Some(codec) = &profile.codec {
hash.aset(ruby.sym_new("codec"), codec_to_hash(ruby, codec)?)?;
}
if !profile.grpc_meta.is_empty() {
let grpc_meta_hash = RHash::new();
for (k, v) in &profile.grpc_meta {
grpc_meta_hash.aset(ruby.str_new(k), ruby.str_new(v))?;
}
hash.aset(ruby.sym_new("grpc_meta"), grpc_meta_hash)?;
}

Ok(hash)
}

fn core_config_to_hash(ruby: &Ruby, core_config: &CoreClientConfig) -> Result<RHash, Error> {
let profiles_hash = RHash::new();
for (name, profile) in &core_config.profiles {
let profile_hash = profile_to_hash(ruby, profile)?;
profiles_hash.aset(ruby.str_new(name), profile_hash)?;
}
Ok(profiles_hash)
}

fn load_client_config_inner(
ruby: &Ruby,
config_source: Option<DataSource>,
config_file_strict: bool,
disable_file: bool,
env_vars: Option<HashMap<String, String>>,
) -> Result<RHash, Error> {
let core_config = if disable_file {
CoreClientConfig::default()
} else {
let options = LoadClientConfigOptions {
config_source,
config_file_strict,
};
core_load_client_config(options, env_vars.as_ref())
.map_err(|e| error!("EnvConfig error: {}", e))?
};

core_config_to_hash(ruby, &core_config)
}

fn load_client_connect_config_inner(
ruby: &Ruby,
config_source: Option<DataSource>,
profile: Option<String>,
disable_file: bool,
disable_env: bool,
config_file_strict: bool,
env_vars: Option<HashMap<String, String>>,
) -> Result<RHash, Error> {
let options = LoadClientConfigProfileOptions {
config_source,
config_file_profile: profile,
config_file_strict,
disable_file,
disable_env,
};

let profile = core_load_client_config_profile(options, env_vars.as_ref())
.map_err(|e| error!("EnvConfig error: {}", e))?;

profile_to_hash(ruby, &profile)
}

// load_client_config(path: String|nil, data: String|nil, disable_file: bool, config_file_strict: bool, env_vars: Hash|nil)
fn load_client_config(args: &[magnus::Value]) -> Result<RHash, Error> {
let ruby = Ruby::get().expect("Not in Ruby thread");
let args = scan_args::scan_args::<
(Option<String>, Option<RString>, bool, bool),
(Option<HashMap<String, String>>,),
(),
(),
(),
(),
>(args)?;
let (path, data, disable_file, config_file_strict) = args.required;
let (env_vars,) = args.optional;

let config_source = match (path, data) {
(Some(p), None) => Some(DataSource::Path(p)),
(None, Some(d)) => {
let bytes = unsafe { d.as_slice().to_vec() };
Some(DataSource::Data(bytes))
}
(None, None) => None,
(Some(_), Some(_)) => {
return Err(error!(
"Cannot specify both path and data for config source"
));
}
};

load_client_config_inner(
&ruby,
config_source,
config_file_strict,
disable_file,
env_vars,
)
}

// load_client_connect_config(profile: String|nil, path: String|nil, data: String|nil, disable_file: bool, disable_env: bool, config_file_strict: bool, env_vars: Hash|nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to just accept a defined-in-Ruby struct options set as we do in other Rust-from-Ruby calls if that makes it cleaner once it gets to this many parameters

fn load_client_connect_config(args: &[magnus::Value]) -> Result<RHash, Error> {
let ruby = Ruby::get().expect("Not in Ruby thread");
let args = scan_args::scan_args::<
(
Option<String>,
Option<String>,
Option<RString>,
bool,
bool,
bool,
),
(Option<HashMap<String, String>>,),
(),
(),
(),
(),
>(args)?;
let (profile, path, data, disable_file, disable_env, config_file_strict) = args.required;
let (env_vars,) = args.optional;

let config_source = match (path, data) {
(Some(p), None) => Some(DataSource::Path(p)),
(None, Some(d)) => {
let bytes = unsafe { d.as_slice().to_vec() };
Some(DataSource::Data(bytes))
}
(None, None) => None,
(Some(_), Some(_)) => {
return Err(error!(
"Cannot specify both path and data for config source"
));
}
};

load_client_connect_config_inner(
&ruby,
config_source,
profile,
disable_file,
disable_env,
config_file_strict,
env_vars,
)
}
2 changes: 2 additions & 0 deletions temporalio/ext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use magnus::{Error, ExceptionClass, RModule, Ruby, prelude::*, value::Lazy};

mod client;
mod client_rpc_generated;
mod envconfig;
mod metric;
mod runtime;
mod testing;
Expand Down Expand Up @@ -50,6 +51,7 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
Lazy::force(&ROOT_ERR, ruby);

client::init(ruby)?;
envconfig::init(ruby)?;
metric::init(ruby)?;
runtime::init(ruby)?;
testing::init(ruby)?;
Expand Down
4 changes: 2 additions & 2 deletions temporalio/lib/temporalio/cancellation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ def prepare_cancel(reason:)
to_return.values
end

def canceled_mutex_synchronize(&)
Workflow::Unsafe.illegal_call_tracing_disabled { @canceled_mutex.synchronize(&) }
def canceled_mutex_synchronize(&block)
Workflow::Unsafe.illegal_call_tracing_disabled { @canceled_mutex.synchronize(&block) }
end
end
end
Loading
Loading