Skip to content

Commit b0a8cc6

Browse files
authored
Merge pull request #12 from configcat/sdk-improvements
Sdk improvements
2 parents c8a6659 + 3795ad7 commit b0a8cc6

19 files changed

+667
-171
lines changed

lib/configcat.rb

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ def ConfigCat.create_client_with_auto_poll(sdk_key,
3333
proxy_port: nil,
3434
proxy_user: nil,
3535
proxy_pass: nil,
36+
open_timeout: 10,
37+
read_timeout: 30,
38+
flag_overrides: nil,
3639
data_governance: DataGovernance::GLOBAL)
3740
#
3841
# Create an instance of ConfigCatClient and setup Auto Poll mode with custom options
@@ -48,6 +51,9 @@ def ConfigCat.create_client_with_auto_poll(sdk_key,
4851
# :param proxy_port: Proxy port
4952
# :param proxy_user: username for proxy authentication
5053
# :param proxy_pass: password for proxy authentication
54+
# :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
55+
# :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
56+
# :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
5157
# :param data_governance:
5258
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
5359
# https://app.configcat.com/organization/data-governance
@@ -73,6 +79,9 @@ def ConfigCat.create_client_with_auto_poll(sdk_key,
7379
proxy_port: proxy_port,
7480
proxy_user: proxy_user,
7581
proxy_pass: proxy_pass,
82+
open_timeout: open_timeout,
83+
read_timeout: read_timeout,
84+
flag_overrides: flag_overrides,
7685
data_governance: data_governance)
7786
end
7887

@@ -84,6 +93,9 @@ def ConfigCat.create_client_with_lazy_load(sdk_key,
8493
proxy_port: nil,
8594
proxy_user: nil,
8695
proxy_pass: nil,
96+
open_timeout: 10,
97+
read_timeout: 30,
98+
flag_overrides: nil,
8799
data_governance: DataGovernance::GLOBAL)
88100
#
89101
# Create an instance of ConfigCatClient and setup Lazy Load mode with custom options
@@ -97,6 +109,9 @@ def ConfigCat.create_client_with_lazy_load(sdk_key,
97109
# :param proxy_port: Proxy port
98110
# :param proxy_user: username for proxy authentication
99111
# :param proxy_pass: password for proxy authentication
112+
# :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
113+
# :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
114+
# :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
100115
# :param data_governance:
101116
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
102117
# https://app.configcat.com/organization/data-governance
@@ -119,16 +134,22 @@ def ConfigCat.create_client_with_lazy_load(sdk_key,
119134
proxy_port: proxy_port,
120135
proxy_user: proxy_user,
121136
proxy_pass: proxy_pass,
137+
open_timeout: open_timeout,
138+
read_timeout: read_timeout,
139+
flag_overrides: flag_overrides,
122140
data_governance: data_governance)
123141
end
124142

125143
def ConfigCat.create_client_with_manual_poll(sdk_key,
126144
config_cache_class: nil,
127145
base_url: nil,
128-
proxy_address:nil,
129-
proxy_port:nil,
130-
proxy_user:nil,
131-
proxy_pass:nil,
146+
proxy_address: nil,
147+
proxy_port: nil,
148+
proxy_user: nil,
149+
proxy_pass: nil,
150+
open_timeout: 10,
151+
read_timeout: 30,
152+
flag_overrides: nil,
132153
data_governance: DataGovernance::GLOBAL)
133154
#
134155
# Create an instance of ConfigCatClient and setup Manual Poll mode with custom options
@@ -141,6 +162,9 @@ def ConfigCat.create_client_with_manual_poll(sdk_key,
141162
# :param proxy_port: Proxy port
142163
# :param proxy_user: username for proxy authentication
143164
# :param proxy_pass: password for proxy authentication
165+
# :param open_timeout: The number of seconds to wait for the server to make the initial connection. Default: 10 seconds.
166+
# :param read_timeout: The number of seconds to wait for the server to respond before giving up. Default: 30 seconds.
167+
# :param flag_overrides: An OverrideDataSource implementation used to override feature flags & settings.
144168
# :param data_governance:
145169
# Default: Global. Set this parameter to be in sync with the Data Governance preference on the Dashboard:
146170
# https://app.configcat.com/organization/data-governance
@@ -160,6 +184,9 @@ def ConfigCat.create_client_with_manual_poll(sdk_key,
160184
proxy_port: proxy_port,
161185
proxy_user: proxy_user,
162186
proxy_pass: proxy_pass,
187+
open_timeout: open_timeout,
188+
read_timeout: read_timeout,
189+
flag_overrides: flag_overrides,
163190
data_governance: data_governance)
164191
end
165192

lib/configcat/autopollingcachepolicy.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ def force_refresh()
8282
if !@_initialized && !old_configuration.equal?(nil)
8383
@_initialized = true
8484
end
85+
rescue Timeout::Error => e
86+
ConfigCat.logger.error("Request timed out. Timeout values: [open: %ss, read: %ss]" %
87+
[@_config_fetcher.get_open_timeout(), @_config_fetcher.get_read_timeout()])
8588
rescue Exception => e
8689
ConfigCat.logger.error("Double-check your SDK Key at https://app.configcat.com/sdkkey.")
8790
ConfigCat.logger.error "threw exception #{e.class}:'#{e}'"

lib/configcat/configcatclient.rb

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,57 +7,85 @@
77
require 'configcat/rolloutevaluator'
88
require 'configcat/datagovernance'
99

10+
1011
module ConfigCat
1112
KeyValue = Struct.new(:key, :value)
1213
class ConfigCatClient
14+
@@sdk_keys = []
15+
1316
def initialize(sdk_key,
14-
poll_interval_seconds:60,
15-
max_init_wait_time_seconds:5,
16-
on_configuration_changed_callback:nil,
17-
cache_time_to_live_seconds:60,
18-
config_cache_class:nil,
19-
base_url:nil,
20-
proxy_address:nil,
21-
proxy_port:nil,
22-
proxy_user:nil,
23-
proxy_pass:nil,
17+
poll_interval_seconds: 60,
18+
max_init_wait_time_seconds: 5,
19+
on_configuration_changed_callback: nil,
20+
cache_time_to_live_seconds: 60,
21+
config_cache_class: nil,
22+
base_url: nil,
23+
proxy_address: nil,
24+
proxy_port: nil,
25+
proxy_user: nil,
26+
proxy_pass: nil,
27+
open_timeout: 10,
28+
read_timeout: 30,
29+
flag_overrides: nil,
2430
data_governance: DataGovernance::GLOBAL)
2531
if sdk_key === nil
2632
raise ConfigCatClientException, "SDK Key is required."
2733
end
34+
35+
if @@sdk_keys.include?(sdk_key)
36+
ConfigCat.logger.warn("A ConfigCat Client is already initialized with sdk_key %s. "\
37+
"We strongly recommend you to use the ConfigCat Client as "\
38+
"a Singleton object in your application." % sdk_key)
39+
else
40+
@@sdk_keys.push(sdk_key)
41+
end
42+
2843
@_sdk_key = sdk_key
44+
@_override_data_source = flag_overrides
2945

3046
if config_cache_class
3147
@_config_cache = config_cache_class.new()
3248
else
3349
@_config_cache = InMemoryConfigCache.new()
3450
end
3551

36-
if poll_interval_seconds > 0
37-
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
52+
if !@_override_data_source.equal?(nil) && @_override_data_source.get_behaviour() == OverrideBehaviour::LOCAL_ONLY
53+
@_config_fetcher = nil
54+
@_cache_policy = nil
55+
elsif poll_interval_seconds > 0
56+
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "p", base_url: base_url,
57+
proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
58+
open_timeout: open_timeout, read_timeout: read_timeout,
59+
data_governance: data_governance)
3860
@_cache_policy = AutoPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), poll_interval_seconds, max_init_wait_time_seconds, on_configuration_changed_callback)
61+
elsif cache_time_to_live_seconds > 0
62+
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url: base_url,
63+
proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
64+
open_timeout: open_timeout, read_timeout: read_timeout,
65+
data_governance: data_governance)
66+
@_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), cache_time_to_live_seconds)
3967
else
40-
if cache_time_to_live_seconds > 0
41-
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "l", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
42-
@_cache_policy = LazyLoadingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key(), cache_time_to_live_seconds)
43-
else
44-
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "m", base_url, proxy_address, proxy_port, proxy_user, proxy_pass, data_governance)
45-
@_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key())
46-
end
68+
@_config_fetcher = CacheControlConfigFetcher.new(sdk_key, "m", base_url: base_url,
69+
proxy_address: proxy_address, proxy_port: proxy_port, proxy_user: proxy_user, proxy_pass: proxy_pass,
70+
open_timeout: open_timeout, read_timeout: read_timeout,
71+
data_governance: data_governance)
72+
@_cache_policy = ManualPollingCachePolicy.new(@_config_fetcher, @_config_cache, _get_cache_key())
4773
end
4874
end
4975

5076
def get_value(key, default_value, user=nil)
51-
config = @_cache_policy.get()
77+
config = _get_settings()
5278
if config === nil
79+
ConfigCat.logger.warn("Evaluating get_value('%s') failed. Cache is empty. "\
80+
"Returning default_value in your get_value call: [%s]." % [key, default_value.to_s])
5381
return default_value
5482
end
5583
value, variation_id = RolloutEvaluator.evaluate(key, user, default_value, nil, config)
5684
return value
5785
end
5886

5987
def get_all_keys()
60-
config = @_cache_policy.get()
88+
config = _get_settings()
6189
if config === nil
6290
return []
6391
end
@@ -69,7 +97,7 @@ def get_all_keys()
6997
end
7098

7199
def get_variation_id(key, default_variation_id, user=nil)
72-
config = @_cache_policy.get()
100+
config = _get_settings()
73101
if config === nil
74102
ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. "\
75103
"Returning default_variation_id in your get_variation_id call: [%s]." %
@@ -93,7 +121,7 @@ def get_all_variation_ids(user: nil)
93121
end
94122

95123
def get_key_and_value(variation_id)
96-
config = @_cache_policy.get()
124+
config = _get_settings()
97125
if config === nil
98126
ConfigCat.logger.warn("Evaluating get_variation_id('%s') failed. Cache is empty. Returning nil." % variation_id)
99127
return nil
@@ -126,17 +154,56 @@ def get_key_and_value(variation_id)
126154
end
127155
end
128156

157+
def get_all_values(user: nil)
158+
keys = get_all_keys()
159+
all_values = {}
160+
for key in keys
161+
value = get_value(key, nil, user)
162+
if !value.equal?(nil)
163+
all_values[key] = value
164+
end
165+
end
166+
return all_values
167+
end
168+
129169
def force_refresh()
130170
@_cache_policy.force_refresh()
131171
end
132172

133173
def stop()
134-
@_cache_policy.stop()
135-
@_config_fetcher.close()
174+
@_cache_policy.stop() if @_cache_policy
175+
@_config_fetcher.close() if @_config_fetcher
176+
@@sdk_keys.delete(@_sdk_key)
136177
end
137178

138179
private
139180

181+
def _get_settings()
182+
if !@_override_data_source.nil?
183+
behaviour = @_override_data_source.get_behaviour()
184+
if behaviour == OverrideBehaviour::LOCAL_ONLY
185+
return @_override_data_source.get_overrides()
186+
elsif behaviour == OverrideBehaviour::REMOTE_OVER_LOCAL
187+
remote_settings = @_cache_policy.get()
188+
local_settings = @_override_data_source.get_overrides()
189+
result = local_settings.clone()
190+
if remote_settings.key?(FEATURE_FLAGS) && local_settings.key?(FEATURE_FLAGS)
191+
result[FEATURE_FLAGS] = result[FEATURE_FLAGS].merge(remote_settings[FEATURE_FLAGS])
192+
end
193+
return result
194+
elsif behaviour == OverrideBehaviour::LOCAL_OVER_REMOTE
195+
remote_settings = @_cache_policy.get()
196+
local_settings = @_override_data_source.get_overrides()
197+
result = remote_settings.clone()
198+
if remote_settings.key?(FEATURE_FLAGS) && local_settings.key?(FEATURE_FLAGS)
199+
result[FEATURE_FLAGS] = result[FEATURE_FLAGS].merge(local_settings[FEATURE_FLAGS])
200+
end
201+
return result
202+
end
203+
end
204+
return @_cache_policy.get()
205+
end
206+
140207
def _get_cache_key()
141208
return Digest::SHA1.hexdigest("ruby_" + CONFIG_FILE_NAME + "_" + @_sdk_key)
142209
end

lib/configcat/configfetcher.rb

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,16 @@ def is_not_modified()
4141
end
4242

4343
class CacheControlConfigFetcher < ConfigFetcher
44-
def initialize(sdk_key, mode, base_url=nil, proxy_address=nil, proxy_port=nil, proxy_user=nil, proxy_pass=nil,
45-
data_governance=DataGovernance::GLOBAL)
44+
def initialize(sdk_key, mode, base_url:nil, proxy_address:nil, proxy_port:nil, proxy_user:nil, proxy_pass:nil,
45+
open_timeout:10, read_timeout:30,
46+
data_governance:DataGovernance::GLOBAL)
4647
@_sdk_key = sdk_key
4748
@_proxy_address = proxy_address
4849
@_proxy_port = proxy_port
4950
@_proxy_user = proxy_user
5051
@_proxy_pass = proxy_pass
52+
@_open_timeout = open_timeout
53+
@_read_timeout = read_timeout
5154
@_etag = ""
5255
@_headers = {"User-Agent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "X-ConfigCat-UserAgent" => ((("ConfigCat-Ruby/") + mode) + ("-")) + VERSION, "Content-Type" => "application/json"}
5356
if !base_url.equal?(nil)
@@ -63,6 +66,14 @@ def initialize(sdk_key, mode, base_url=nil, proxy_address=nil, proxy_port=nil, p
6366
end
6467
end
6568

69+
def get_open_timeout()
70+
return @_open_timeout
71+
end
72+
73+
def get_read_timeout()
74+
return @_read_timeout
75+
end
76+
6677
# Returns the FetchResponse object contains configuration json Dictionary
6778
def get_configuration_json(retries=0)
6879
ConfigCat.logger.debug "Fetching configuration from ConfigCat"
@@ -141,8 +152,8 @@ def _create_http()
141152
close()
142153
@_http = Net::HTTP.new(uri.host, uri.port, @_proxy_address, @_proxy_port, @_proxy_user, @_proxy_pass)
143154
@_http.use_ssl = use_ssl
144-
@_http.open_timeout = 10 # in seconds
145-
@_http.read_timeout = 30 # in seconds
155+
@_http.open_timeout = @_open_timeout
156+
@_http.read_timeout = @_read_timeout
146157
end
147158
end
148159
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
require 'configcat/overridedatasource'
2+
require 'configcat/constants'
3+
4+
5+
module ConfigCat
6+
class LocalDictionaryDataSource < OverrideDataSource
7+
def initialize(source, override_behaviour)
8+
super(override_behaviour)
9+
dictionary = {}
10+
source.each do |key, value|
11+
dictionary[key] = {VALUE => value}
12+
end
13+
@_settings = {FEATURE_FLAGS => dictionary}
14+
end
15+
16+
def get_overrides()
17+
return @_settings
18+
end
19+
end
20+
end

0 commit comments

Comments
 (0)