eppo-server-sdk 3.1.2 → 3.2.2
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/Cargo.lock +20 -9
- data/Rakefile +2 -13
- data/build/x86-64_linux-setup.sh +17 -0
- data/ext/eppo_client/Cargo.toml +5 -4
- data/ext/eppo_client/src/client.rs +50 -20
- data/ext/eppo_client/src/configuration.rs +113 -0
- data/ext/eppo_client/src/gc_lock.rs +25 -0
- data/ext/eppo_client/src/lib.rs +21 -1
- data/lib/eppo_client/client.rb +8 -0
- data/lib/eppo_client/config.rb +4 -2
- data/lib/eppo_client/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 58a6e5ef2e00c9c830661f2571eab4f6817e2ceaf40de3dd541b7f2421fb24c0
|
|
4
|
+
data.tar.gz: 8616534de1a08cd7c9d02570da27b15c64e4df0e2c805301bd3f4e54f1b6d3d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 23fe167a77c13f00137469b6bf078cb27e907dc1a5b4d18cc6f9bcfbda0a60f9620425d92eca98f3a4d2034796cd5b7f09bf9d08f6a61e0c9fa66b14c5f3730b
|
|
7
|
+
data.tar.gz: 9722bfdd197f648bcfd82b9f93f232c834d8c17a43b73b221bcfe47927b2dc2ed81cf3a95ad856b6497479861f82093b7127e9bbaa814d39bca48c2fd6662977
|
data/Cargo.lock
CHANGED
|
@@ -304,7 +304,7 @@ dependencies = [
|
|
|
304
304
|
|
|
305
305
|
[[package]]
|
|
306
306
|
name = "eppo_client"
|
|
307
|
-
version = "3.
|
|
307
|
+
version = "3.2.2"
|
|
308
308
|
dependencies = [
|
|
309
309
|
"env_logger",
|
|
310
310
|
"eppo_core",
|
|
@@ -312,14 +312,15 @@ dependencies = [
|
|
|
312
312
|
"magnus",
|
|
313
313
|
"rb-sys",
|
|
314
314
|
"serde",
|
|
315
|
+
"serde_json",
|
|
315
316
|
"serde_magnus",
|
|
316
317
|
]
|
|
317
318
|
|
|
318
319
|
[[package]]
|
|
319
320
|
name = "eppo_core"
|
|
320
|
-
version = "4.
|
|
321
|
+
version = "4.1.0"
|
|
321
322
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
322
|
-
checksum = "
|
|
323
|
+
checksum = "626df025f5b474b42ead14953310e31e81e4b88ce52a993573bf87bc9def12d4"
|
|
323
324
|
dependencies = [
|
|
324
325
|
"chrono",
|
|
325
326
|
"derive_more",
|
|
@@ -906,6 +907,15 @@ version = "0.1.5"
|
|
|
906
907
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
907
908
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|
908
909
|
|
|
910
|
+
[[package]]
|
|
911
|
+
name = "openssl-src"
|
|
912
|
+
version = "300.3.1+3.3.1"
|
|
913
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
914
|
+
checksum = "7259953d42a81bf137fbbd73bd30a8e1914d6dce43c2b90ed575783a22608b91"
|
|
915
|
+
dependencies = [
|
|
916
|
+
"cc",
|
|
917
|
+
]
|
|
918
|
+
|
|
909
919
|
[[package]]
|
|
910
920
|
name = "openssl-sys"
|
|
911
921
|
version = "0.9.103"
|
|
@@ -914,6 +924,7 @@ checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
|
|
|
914
924
|
dependencies = [
|
|
915
925
|
"cc",
|
|
916
926
|
"libc",
|
|
927
|
+
"openssl-src",
|
|
917
928
|
"pkg-config",
|
|
918
929
|
"vcpkg",
|
|
919
930
|
]
|
|
@@ -1021,18 +1032,18 @@ dependencies = [
|
|
|
1021
1032
|
|
|
1022
1033
|
[[package]]
|
|
1023
1034
|
name = "rb-sys"
|
|
1024
|
-
version = "0.9.
|
|
1035
|
+
version = "0.9.102"
|
|
1025
1036
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1026
|
-
checksum = "
|
|
1037
|
+
checksum = "df4dec4b1d304c3b308a2cd86b1216ea45dd4361f4e9fa056f108332d0a450c1"
|
|
1027
1038
|
dependencies = [
|
|
1028
1039
|
"rb-sys-build",
|
|
1029
1040
|
]
|
|
1030
1041
|
|
|
1031
1042
|
[[package]]
|
|
1032
1043
|
name = "rb-sys-build"
|
|
1033
|
-
version = "0.9.
|
|
1044
|
+
version = "0.9.102"
|
|
1034
1045
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1035
|
-
checksum = "
|
|
1046
|
+
checksum = "1d71de3e29d174b8fb17b5d4470f27d7aa2605f8a9d05fda0d3aeff30e05a570"
|
|
1036
1047
|
dependencies = [
|
|
1037
1048
|
"bindgen",
|
|
1038
1049
|
"lazy_static",
|
|
@@ -1295,9 +1306,9 @@ dependencies = [
|
|
|
1295
1306
|
|
|
1296
1307
|
[[package]]
|
|
1297
1308
|
name = "serde_json"
|
|
1298
|
-
version = "1.0.
|
|
1309
|
+
version = "1.0.128"
|
|
1299
1310
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1300
|
-
checksum = "
|
|
1311
|
+
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
|
1301
1312
|
dependencies = [
|
|
1302
1313
|
"itoa",
|
|
1303
1314
|
"memchr",
|
data/Rakefile
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "bundler/gem_tasks"
|
|
4
|
-
require "rspec/core/rake_task"
|
|
5
4
|
require_relative 'lib/eppo_client/version'
|
|
6
5
|
|
|
7
6
|
GEM_NAME = 'eppo-server-sdk'
|
|
8
7
|
GEM_VERSION = EppoClient::VERSION
|
|
9
8
|
|
|
10
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
11
|
-
|
|
12
|
-
require "rubocop/rake_task"
|
|
13
|
-
|
|
14
|
-
RuboCop::RakeTask.new
|
|
15
|
-
|
|
16
9
|
require "rb_sys/extensiontask"
|
|
17
10
|
|
|
18
11
|
task default: :build
|
|
@@ -21,6 +14,8 @@ GEMSPEC = Gem::Specification.load("eppo-server-sdk.gemspec")
|
|
|
21
14
|
|
|
22
15
|
RbSys::ExtensionTask.new("eppo_client", GEMSPEC) do |ext|
|
|
23
16
|
ext.lib_dir = "lib/eppo_client"
|
|
17
|
+
|
|
18
|
+
ext.cross_compile = true
|
|
24
19
|
end
|
|
25
20
|
|
|
26
21
|
task build: :compile do
|
|
@@ -43,11 +38,5 @@ task :clean do
|
|
|
43
38
|
system 'rm *.gem'
|
|
44
39
|
end
|
|
45
40
|
|
|
46
|
-
RSpec::Core::RakeTask.new(:test) do |task|
|
|
47
|
-
root_dir = Rake.application.original_dir
|
|
48
|
-
task.pattern = "#{root_dir}/spec/*_spec.rb"
|
|
49
|
-
task.verbose = false
|
|
50
|
-
end
|
|
51
|
-
|
|
52
41
|
task test: :devinstall
|
|
53
42
|
task test_refreshed_data: [:devinstall, 'test-data']
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
## From:
|
|
4
|
+
## https://github.com/BoundaryML/baml/blob/canary/engine/language_client_ruby/x86-64_linux-setup.sh
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
set -euxo pipefail
|
|
8
|
+
|
|
9
|
+
# from https://serverfault.com/questions/1161816/mirrorlist-centos-org-no-longer-resolve
|
|
10
|
+
sudo sed -i 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/*.repo
|
|
11
|
+
sudo sed -i 's/^#.*baseurl=http/baseurl=http/g' /etc/yum.repos.d/*.repo
|
|
12
|
+
sudo sed -i 's/^mirrorlist=http/#mirrorlist=http/g' /etc/yum.repos.d/*.repo
|
|
13
|
+
|
|
14
|
+
ls /etc/yum.repos.d/
|
|
15
|
+
|
|
16
|
+
# We need this to build engine/, since it's needed for OpenSSL
|
|
17
|
+
sudo yum install -y perl-IPC-Cmd
|
data/ext/eppo_client/Cargo.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "eppo_client"
|
|
3
3
|
# TODO: this version and lib/eppo_client/version.rb should be in sync
|
|
4
|
-
version = "3.
|
|
4
|
+
version = "3.2.2"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
publish = false
|
|
@@ -12,9 +12,10 @@ crate-type = ["cdylib"]
|
|
|
12
12
|
|
|
13
13
|
[dependencies]
|
|
14
14
|
env_logger = { version = "0.11.3", features = ["unstable-kv"] }
|
|
15
|
-
eppo_core = { version = "4.
|
|
15
|
+
eppo_core = { version = "4.1.0", features = ["vendored"] }
|
|
16
16
|
log = { version = "0.4.21", features = ["kv_serde"] }
|
|
17
|
-
magnus = { version = "0.6.
|
|
17
|
+
magnus = { version = "0.6.4" }
|
|
18
18
|
serde = { version = "1.0.203", features = ["derive"] }
|
|
19
19
|
serde_magnus = "0.8.1"
|
|
20
|
-
rb-sys = "0.9"
|
|
20
|
+
rb-sys = "0.9.102"
|
|
21
|
+
serde_json = "1.0.128"
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
use std::{cell::RefCell, sync::Arc};
|
|
1
|
+
use std::{cell::RefCell, sync::Arc, time::Duration};
|
|
2
2
|
|
|
3
3
|
use eppo_core::{
|
|
4
4
|
configuration_fetcher::{ConfigurationFetcher, ConfigurationFetcherConfig},
|
|
5
5
|
configuration_store::ConfigurationStore,
|
|
6
6
|
eval::{Evaluator, EvaluatorConfig},
|
|
7
|
-
poller_thread::PollerThread,
|
|
7
|
+
poller_thread::{PollerThread, PollerThreadConfig},
|
|
8
8
|
ufc::VariationType,
|
|
9
|
-
Attributes, ContextAttributes,
|
|
9
|
+
Attributes, ContextAttributes,
|
|
10
10
|
};
|
|
11
11
|
use magnus::{error::Result, exception, prelude::*, Error, TryConvert, Value};
|
|
12
12
|
|
|
13
|
+
use crate::{configuration::Configuration, SDK_METADATA};
|
|
14
|
+
|
|
13
15
|
#[derive(Debug)]
|
|
14
16
|
#[magnus::wrap(class = "EppoClient::Core::Config", size, free_immediately)]
|
|
15
17
|
pub struct Config {
|
|
16
18
|
api_key: String,
|
|
17
19
|
base_url: String,
|
|
20
|
+
poll_interval: Option<Duration>,
|
|
21
|
+
poll_jitter: Duration,
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
impl TryConvert for Config {
|
|
@@ -22,12 +26,21 @@ impl TryConvert for Config {
|
|
|
22
26
|
fn try_convert(val: magnus::Value) -> Result<Self> {
|
|
23
27
|
let api_key = String::try_convert(val.funcall("api_key", ())?)?;
|
|
24
28
|
let base_url = String::try_convert(val.funcall("base_url", ())?)?;
|
|
25
|
-
|
|
29
|
+
let poll_interval_seconds =
|
|
30
|
+
Option::<u64>::try_convert(val.funcall("poll_interval_seconds", ())?)?;
|
|
31
|
+
let poll_jitter_seconds = u64::try_convert(val.funcall("poll_jitter_seconds", ())?)?;
|
|
32
|
+
Ok(Config {
|
|
33
|
+
api_key,
|
|
34
|
+
base_url,
|
|
35
|
+
poll_interval: poll_interval_seconds.map(Duration::from_secs),
|
|
36
|
+
poll_jitter: Duration::from_secs(poll_jitter_seconds),
|
|
37
|
+
})
|
|
26
38
|
}
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
#[magnus::wrap(class = "EppoClient::Core::Client")]
|
|
30
42
|
pub struct Client {
|
|
43
|
+
configuration_store: Arc<ConfigurationStore>,
|
|
31
44
|
evaluator: Evaluator,
|
|
32
45
|
// Magnus only allows sharing aliased references (&T) through the API, so we need to use RefCell
|
|
33
46
|
// to get interior mutability.
|
|
@@ -41,29 +54,35 @@ impl Client {
|
|
|
41
54
|
pub fn new(config: Config) -> Client {
|
|
42
55
|
let configuration_store = Arc::new(ConfigurationStore::new());
|
|
43
56
|
|
|
44
|
-
let
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
let poller_thread = if let Some(poll_interval) = config.poll_interval {
|
|
58
|
+
Some(
|
|
59
|
+
PollerThread::start_with_config(
|
|
60
|
+
ConfigurationFetcher::new(ConfigurationFetcherConfig {
|
|
61
|
+
base_url: config.base_url,
|
|
62
|
+
api_key: config.api_key,
|
|
63
|
+
sdk_metadata: SDK_METADATA,
|
|
64
|
+
}),
|
|
65
|
+
configuration_store.clone(),
|
|
66
|
+
PollerThreadConfig {
|
|
67
|
+
interval: poll_interval,
|
|
68
|
+
jitter: config.poll_jitter,
|
|
69
|
+
},
|
|
70
|
+
)
|
|
71
|
+
.expect("should be able to start poller thread"),
|
|
72
|
+
)
|
|
73
|
+
} else {
|
|
74
|
+
None
|
|
47
75
|
};
|
|
48
76
|
|
|
49
|
-
let poller_thread = PollerThread::start(
|
|
50
|
-
ConfigurationFetcher::new(ConfigurationFetcherConfig {
|
|
51
|
-
base_url: config.base_url,
|
|
52
|
-
api_key: config.api_key,
|
|
53
|
-
sdk_metadata: sdk_metadata.clone(),
|
|
54
|
-
}),
|
|
55
|
-
configuration_store.clone(),
|
|
56
|
-
)
|
|
57
|
-
.expect("should be able to start poller thread");
|
|
58
|
-
|
|
59
77
|
let evaluator = Evaluator::new(EvaluatorConfig {
|
|
60
|
-
configuration_store,
|
|
61
|
-
sdk_metadata,
|
|
78
|
+
configuration_store: configuration_store.clone(),
|
|
79
|
+
sdk_metadata: SDK_METADATA,
|
|
62
80
|
});
|
|
63
81
|
|
|
64
82
|
Client {
|
|
83
|
+
configuration_store,
|
|
65
84
|
evaluator,
|
|
66
|
-
poller_thread: RefCell::new(
|
|
85
|
+
poller_thread: RefCell::new(poller_thread),
|
|
67
86
|
}
|
|
68
87
|
}
|
|
69
88
|
|
|
@@ -171,6 +190,17 @@ impl Client {
|
|
|
171
190
|
serde_magnus::serialize(&result)
|
|
172
191
|
}
|
|
173
192
|
|
|
193
|
+
pub fn get_configuration(&self) -> Option<Configuration> {
|
|
194
|
+
self.configuration_store
|
|
195
|
+
.get_configuration()
|
|
196
|
+
.map(|it| it.into())
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
pub fn set_configuration(&self, configuration: &Configuration) {
|
|
200
|
+
self.configuration_store
|
|
201
|
+
.set_configuration(configuration.clone().into())
|
|
202
|
+
}
|
|
203
|
+
|
|
174
204
|
pub fn shutdown(&self) {
|
|
175
205
|
if let Some(t) = self.poller_thread.take() {
|
|
176
206
|
let _ = t.shutdown();
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
use std::sync::Arc;
|
|
2
|
+
|
|
3
|
+
use magnus::{function, method, prelude::*, scan_args::get_kwargs, Error, RHash, RString, Ruby};
|
|
4
|
+
|
|
5
|
+
use eppo_core::{ufc::UniversalFlagConfig, Configuration as CoreConfiguration};
|
|
6
|
+
|
|
7
|
+
use crate::{gc_lock::GcLock, SDK_METADATA};
|
|
8
|
+
|
|
9
|
+
pub(crate) fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
10
|
+
let eppo_client = ruby.define_module("EppoClient")?;
|
|
11
|
+
|
|
12
|
+
let configuration = eppo_client.define_class("Configuration", magnus::class::object())?;
|
|
13
|
+
configuration.define_singleton_method("new", function!(Configuration::new, 1))?;
|
|
14
|
+
configuration.define_method(
|
|
15
|
+
"flags_configuration",
|
|
16
|
+
method!(Configuration::flags_configuration, 0),
|
|
17
|
+
)?;
|
|
18
|
+
configuration.define_method(
|
|
19
|
+
"bandits_configuration",
|
|
20
|
+
method!(Configuration::bandits_configuration, 0),
|
|
21
|
+
)?;
|
|
22
|
+
|
|
23
|
+
Ok(())
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#[derive(Debug, Clone)]
|
|
27
|
+
#[magnus::wrap(class = "EppoClient::Configuration", free_immediately)]
|
|
28
|
+
pub struct Configuration {
|
|
29
|
+
inner: Arc<CoreConfiguration>,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
impl Configuration {
|
|
33
|
+
fn new(ruby: &Ruby, kw: RHash) -> Result<Configuration, Error> {
|
|
34
|
+
let args = get_kwargs(kw, &["flags_configuration"], &["bandits_configuration"])?;
|
|
35
|
+
let (flags_configuration,): (RString,) = args.required;
|
|
36
|
+
let (bandits_configuration,): (Option<Option<RString>>,) = args.optional;
|
|
37
|
+
let rest: RHash = args.splat;
|
|
38
|
+
if !rest.is_empty() {
|
|
39
|
+
return Err(Error::new(
|
|
40
|
+
ruby.exception_arg_error(),
|
|
41
|
+
format!("unexpected keyword arguments: {:?}", rest),
|
|
42
|
+
));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let inner = {
|
|
46
|
+
let _gc_lock = GcLock::new(ruby);
|
|
47
|
+
|
|
48
|
+
Arc::new(CoreConfiguration::from_server_response(
|
|
49
|
+
UniversalFlagConfig::from_json(
|
|
50
|
+
SDK_METADATA,
|
|
51
|
+
unsafe {
|
|
52
|
+
// SAFETY: we have disabled GC, so the memory can't be modified concurrently.
|
|
53
|
+
flags_configuration.as_slice()
|
|
54
|
+
}
|
|
55
|
+
.to_vec(),
|
|
56
|
+
)
|
|
57
|
+
.map_err(|err| {
|
|
58
|
+
Error::new(
|
|
59
|
+
ruby.exception_arg_error(),
|
|
60
|
+
format!("failed to parse flags_configuration: {err:?}"),
|
|
61
|
+
)
|
|
62
|
+
})?,
|
|
63
|
+
bandits_configuration
|
|
64
|
+
.flatten()
|
|
65
|
+
.map(|bandits| {
|
|
66
|
+
serde_json::from_slice(unsafe {
|
|
67
|
+
// SAFETY: we have disabled GC, so the memory can't be modified concurrently.
|
|
68
|
+
bandits.as_slice()
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
.transpose()
|
|
72
|
+
.map_err(|err| {
|
|
73
|
+
Error::new(
|
|
74
|
+
ruby.exception_arg_error(),
|
|
75
|
+
format!("failed to parse bandits_configuration: {err:?}"),
|
|
76
|
+
)
|
|
77
|
+
})?,
|
|
78
|
+
))
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
Ok(Configuration { inner })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
fn flags_configuration(ruby: &Ruby, rb_self: &Self) -> Result<RString, Error> {
|
|
85
|
+
Ok(ruby.str_from_slice(rb_self.inner.flags.to_json()))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fn bandits_configuration(ruby: &Ruby, rb_self: &Self) -> Result<Option<RString>, Error> {
|
|
89
|
+
let Some(bandits) = &rb_self.inner.bandits else {
|
|
90
|
+
return Ok(None)
|
|
91
|
+
};
|
|
92
|
+
let vec = serde_json::to_vec(bandits).map_err(|err| {
|
|
93
|
+
// this should never happen
|
|
94
|
+
Error::new(
|
|
95
|
+
ruby.exception_runtime_error(),
|
|
96
|
+
format!("failed to serialize bandits configuration: {err:?}"),
|
|
97
|
+
)
|
|
98
|
+
})?;
|
|
99
|
+
Ok(Some(ruby.str_from_slice(&vec)))
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
impl From<Arc<CoreConfiguration>> for Configuration {
|
|
104
|
+
fn from(inner: Arc<CoreConfiguration>) -> Configuration {
|
|
105
|
+
Configuration { inner }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
impl From<Configuration> for Arc<CoreConfiguration> {
|
|
110
|
+
fn from(value: Configuration) -> Arc<CoreConfiguration> {
|
|
111
|
+
value.inner
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
use magnus::Ruby;
|
|
2
|
+
|
|
3
|
+
pub struct GcLock<'a> {
|
|
4
|
+
ruby: &'a Ruby,
|
|
5
|
+
/// Holds `true` if GC was already disabled before acquiring the lock (so it doesn't need to be
|
|
6
|
+
/// re-enabled).
|
|
7
|
+
gc_was_disabled: bool,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl<'a> GcLock<'a> {
|
|
11
|
+
pub fn new(ruby: &'a Ruby) -> GcLock<'a> {
|
|
12
|
+
GcLock {
|
|
13
|
+
ruby,
|
|
14
|
+
gc_was_disabled: ruby.gc_disable(),
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
impl<'a> Drop for GcLock<'a> {
|
|
20
|
+
fn drop(&mut self) {
|
|
21
|
+
if !self.gc_was_disabled {
|
|
22
|
+
self.ruby.gc_enable();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
data/ext/eppo_client/src/lib.rs
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
mod client;
|
|
2
|
+
mod configuration;
|
|
3
|
+
mod gc_lock;
|
|
2
4
|
|
|
5
|
+
use eppo_core::SdkMetadata;
|
|
3
6
|
use magnus::{function, method, prelude::*, Error, Object, Ruby};
|
|
4
7
|
|
|
5
8
|
use crate::client::Client;
|
|
6
9
|
|
|
10
|
+
pub(crate) const SDK_METADATA: SdkMetadata = SdkMetadata {
|
|
11
|
+
name: "ruby",
|
|
12
|
+
version: env!("CARGO_PKG_VERSION"),
|
|
13
|
+
};
|
|
14
|
+
|
|
7
15
|
#[magnus::init]
|
|
8
16
|
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
9
|
-
env_logger::Builder::from_env(env_logger::Env::new().default_filter_or("eppo")).init();
|
|
17
|
+
env_logger::Builder::from_env(env_logger::Env::new().default_filter_or("eppo=debug")).init();
|
|
10
18
|
|
|
11
19
|
let eppo_client = ruby.define_module("EppoClient")?;
|
|
12
20
|
let core = eppo_client.define_module("Core")?;
|
|
@@ -23,12 +31,24 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
23
31
|
"get_bandit_action_details",
|
|
24
32
|
method!(Client::get_bandit_action_details, 5),
|
|
25
33
|
)?;
|
|
34
|
+
core_client.define_method("configuration", method!(Client::get_configuration, 0))?;
|
|
35
|
+
core_client.define_method("configuration=", method!(Client::set_configuration, 1))?;
|
|
26
36
|
core_client.define_method("shutdown", method!(Client::shutdown, 0))?;
|
|
27
37
|
|
|
28
38
|
core.const_set(
|
|
29
39
|
"DEFAULT_BASE_URL",
|
|
30
40
|
eppo_core::configuration_fetcher::DEFAULT_BASE_URL,
|
|
31
41
|
)?;
|
|
42
|
+
core.const_set(
|
|
43
|
+
"DEFAULT_POLL_INTERVAL_SECONDS",
|
|
44
|
+
eppo_core::poller_thread::PollerThreadConfig::DEFAULT_POLL_INTERVAL.as_secs(),
|
|
45
|
+
)?;
|
|
46
|
+
core.const_set(
|
|
47
|
+
"DEFAULT_POLL_JITTER_SECONDS",
|
|
48
|
+
eppo_core::poller_thread::PollerThreadConfig::DEFAULT_POLL_JITTER.as_secs(),
|
|
49
|
+
)?;
|
|
50
|
+
|
|
51
|
+
configuration::init(ruby)?;
|
|
32
52
|
|
|
33
53
|
Ok(())
|
|
34
54
|
}
|
data/lib/eppo_client/client.rb
CHANGED
|
@@ -24,6 +24,14 @@ module EppoClient
|
|
|
24
24
|
@core = EppoClient::Core::Client.new(config)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def configuration
|
|
28
|
+
@core.configuration
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def configuration=(configuration)
|
|
32
|
+
@core.configuration = configuration
|
|
33
|
+
end
|
|
34
|
+
|
|
27
35
|
def shutdown
|
|
28
36
|
@core.shutdown
|
|
29
37
|
end
|
data/lib/eppo_client/config.rb
CHANGED
|
@@ -6,12 +6,14 @@ require_relative "assignment_logger"
|
|
|
6
6
|
module EppoClient
|
|
7
7
|
# The class for configuring the Eppo client singleton
|
|
8
8
|
class Config
|
|
9
|
-
attr_reader :api_key, :assignment_logger, :base_url
|
|
9
|
+
attr_reader :api_key, :assignment_logger, :base_url, :poll_interval_seconds, :poll_jitter_seconds
|
|
10
10
|
|
|
11
|
-
def initialize(api_key, assignment_logger: AssignmentLogger.new, base_url: EppoClient::Core::DEFAULT_BASE_URL)
|
|
11
|
+
def initialize(api_key, assignment_logger: AssignmentLogger.new, base_url: EppoClient::Core::DEFAULT_BASE_URL, poll_interval_seconds: EppoClient::Core::DEFAULT_POLL_INTERVAL_SECONDS, poll_jitter_seconds: EppoClient::Core::DEFAULT_POLL_JITTER_SECONDS, initial_configuration: nil)
|
|
12
12
|
@api_key = api_key
|
|
13
13
|
@assignment_logger = assignment_logger
|
|
14
14
|
@base_url = base_url
|
|
15
|
+
@poll_interval_seconds = poll_interval_seconds
|
|
16
|
+
@poll_jitter_seconds = poll_jitter_seconds
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
def validate
|
data/lib/eppo_client/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: eppo-server-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eppo
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-10-
|
|
11
|
+
date: 2024-10-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email:
|
|
@@ -27,10 +27,13 @@ files:
|
|
|
27
27
|
- README.md
|
|
28
28
|
- Rakefile
|
|
29
29
|
- Steepfile
|
|
30
|
+
- build/x86-64_linux-setup.sh
|
|
30
31
|
- ext/eppo_client/Cargo.toml
|
|
31
32
|
- ext/eppo_client/build.rs
|
|
32
33
|
- ext/eppo_client/extconf.rb
|
|
33
34
|
- ext/eppo_client/src/client.rs
|
|
35
|
+
- ext/eppo_client/src/configuration.rs
|
|
36
|
+
- ext/eppo_client/src/gc_lock.rs
|
|
34
37
|
- ext/eppo_client/src/lib.rs
|
|
35
38
|
- lib/eppo_client.rb
|
|
36
39
|
- lib/eppo_client/assignment_logger.rb
|