prefab-cloud-ruby 0.20.0 → 0.21.0

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc.sample +3 -0
  3. data/.github/workflows/ruby.yml +4 -0
  4. data/.gitmodules +3 -0
  5. data/Gemfile +12 -12
  6. data/Gemfile.lock +16 -14
  7. data/README.md +1 -1
  8. data/Rakefile +13 -14
  9. data/VERSION +1 -1
  10. data/lib/prefab/auth_interceptor.rb +2 -1
  11. data/lib/prefab/cancellable_interceptor.rb +8 -7
  12. data/lib/prefab/client.rb +33 -24
  13. data/lib/prefab/config_client.rb +55 -66
  14. data/lib/prefab/config_loader.rb +7 -114
  15. data/lib/prefab/config_resolver.rb +27 -57
  16. data/lib/prefab/config_value_unwrapper.rb +23 -0
  17. data/lib/prefab/criteria_evaluator.rb +96 -0
  18. data/lib/prefab/errors/invalid_api_key_error.rb +1 -1
  19. data/lib/prefab/feature_flag_client.rb +13 -145
  20. data/lib/prefab/internal_logger.rb +6 -5
  21. data/lib/prefab/local_config_parser.rb +110 -0
  22. data/lib/prefab/logger_client.rb +26 -31
  23. data/lib/prefab/murmer3.rb +3 -4
  24. data/lib/prefab/noop_cache.rb +5 -7
  25. data/lib/prefab/noop_stats.rb +2 -3
  26. data/lib/prefab/options.rb +11 -9
  27. data/lib/prefab/ratelimit_client.rb +11 -13
  28. data/lib/prefab/sse_logger.rb +3 -2
  29. data/lib/prefab/weighted_value_resolver.rb +42 -0
  30. data/lib/prefab/yaml_config_parser.rb +32 -0
  31. data/lib/prefab-cloud-ruby.rb +7 -2
  32. data/lib/prefab_pb.rb +49 -43
  33. data/lib/prefab_services_pb.rb +0 -1
  34. data/prefab-cloud-ruby.gemspec +28 -19
  35. data/test/.prefab.unit_tests.config.yaml +3 -2
  36. data/test/integration_test.rb +98 -0
  37. data/test/integration_test_helpers.rb +37 -0
  38. data/test/test_client.rb +32 -31
  39. data/test/test_config_client.rb +21 -20
  40. data/test/test_config_loader.rb +48 -37
  41. data/test/test_config_resolver.rb +312 -135
  42. data/test/test_config_value_unwrapper.rb +83 -0
  43. data/test/test_criteria_evaluator.rb +533 -0
  44. data/test/test_feature_flag_client.rb +35 -347
  45. data/test/test_helper.rb +18 -14
  46. data/test/test_integration.rb +33 -0
  47. data/test/test_local_config_parser.rb +78 -0
  48. data/test/test_logger.rb +47 -46
  49. data/test/test_weighted_value_resolver.rb +65 -0
  50. metadata +24 -27
  51. data/lib/prefab/config_helper.rb +0 -31
  52. data/run_test_harness_server.sh +0 -8
  53. data/test/harness_server.rb +0 -64
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d1d4612e27cae5a4e66065a16d8d70cb0b1c7120770eac8c7e09ce3ca0e48e82
4
- data.tar.gz: 1d1f50b6b4605729b93d62194b17ed9a1fca739f435ec2a4e682482a293bffe6
3
+ metadata.gz: a34b06515d401b7e73fd8b6adf77294187d94ea3a1d1909d159ebfd63b4046ad
4
+ data.tar.gz: 6ba449742b1a75517b35a47151452dbdf94c0a8aef0e58a639ae5b2481262d43
5
5
  SHA512:
6
- metadata.gz: ed5a04b2a16a79b0963d9af2dd71955141fdd06e7d73a4897adf74245435cf33239f78b08bbde797b7420b7e988fbb76e5e4333e6da5350f1037502949c469e7
7
- data.tar.gz: 1b6f556bb94a31c272d5cd3c585860cacb4698be61830379c1a1a7e2d2fdcb461c02777e0c6fdb6a2cc939dcb070a27237506bd3c21d69ccd723ec50dccfbf2a
6
+ metadata.gz: 0a32e0ac965c54d634c579de66927d2982cca26d7098daaf3cdfd2dda88bf04bd33265c1e9f85e303d75fc9360f6df202cee256e59a91012b94f0adcf29252aa
7
+ data.tar.gz: 2c37b2cfeef43f44d2dcbe8835ff8ea130393ad98dd9dd61328371972bf1818ab12d932f6bec319a52ec2423f9204762c6305ab3643023a3aa5ea4bfd18974bf
data/.envrc.sample ADDED
@@ -0,0 +1,3 @@
1
+ export AWS_ACCESS_KEY_ID=
2
+ export AWS_SECRET_ACCESS_KEY=
3
+ export PREFAB_INTEGRATION_TEST_API_KEY=
@@ -26,6 +26,8 @@ jobs:
26
26
 
27
27
  steps:
28
28
  - uses: actions/checkout@v3
29
+ with:
30
+ submodules: recursive
29
31
  - name: Set up Ruby
30
32
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
31
33
  # change this to (see https://github.com/ruby/setup-ruby#versioning):
@@ -37,3 +39,5 @@ jobs:
37
39
  bundler-cache: true # runs 'bundle install' and caches installed gems automatically
38
40
  - name: Run tests
39
41
  run: bundle exec rake
42
+ env:
43
+ PREFAB_INTEGRATION_TEST_API_KEY: ${{ secrets.PREFAB_INTEGRATION_TEST_API_KEY }}
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "test/prefab-cloud-integration-test-data"]
2
+ path = test/prefab-cloud-integration-test-data
3
+ url = git@github.com:prefab-cloud/prefab-cloud-integration-test-data
data/Gemfile CHANGED
@@ -1,23 +1,23 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gem 'concurrent-ruby', '~> 1.0', '>= 1.0.5'
4
4
  gem 'faraday'
5
+ gem 'googleapis-common-protos-types', platforms: :ruby
6
+ gem 'google-protobuf', platforms: :ruby
7
+ gem 'grpc', platforms: :ruby
5
8
  gem 'ld-eventsource'
6
- gem 'grpc', :platforms => :ruby
7
- gem 'google-protobuf', :platforms => :ruby
8
- gem 'googleapis-common-protos-types', :platforms => :ruby
9
9
 
10
10
  group :development do
11
11
  gem 'benchmark-ips'
12
- gem 'grpc-tools', :platforms => :ruby
13
- gem "rdoc"
14
- gem "bundler"
15
- gem "juwelier", "~> 2.4.9"
16
- gem "simplecov", ">= 0"
17
- gem 'thin'
12
+ gem 'bundler'
13
+ gem 'grpc-tools', platforms: :ruby
14
+ gem 'juwelier', '~> 2.4.9'
15
+ gem 'rdoc'
16
+ gem 'simplecov', '>= 0'
18
17
  end
19
18
 
20
19
  group :test do
21
- gem "minitest"
22
- gem "minitest-focus"
20
+ gem 'minitest'
21
+ gem 'minitest-focus'
22
+ gem 'minitest-reporters'
23
23
  end
data/Gemfile.lock CHANGED
@@ -3,16 +3,15 @@ GEM
3
3
  specs:
4
4
  addressable (2.8.0)
5
5
  public_suffix (>= 2.0.2, < 5.0)
6
+ ansi (1.5.0)
6
7
  benchmark-ips (2.10.0)
7
8
  builder (3.2.4)
8
9
  concurrent-ruby (1.1.10)
9
- daemons (1.4.1)
10
10
  descendants_tracker (0.0.4)
11
11
  thread_safe (~> 0.3, >= 0.3.1)
12
12
  docile (1.3.5)
13
13
  domain_name (0.5.20190701)
14
14
  unf (>= 0.0.5, < 1.0.0)
15
- eventmachine (1.2.7)
16
15
  faraday (1.3.0)
17
16
  faraday-net_http (~> 1.0)
18
17
  multipart-post (>= 1.2, < 3)
@@ -22,7 +21,8 @@ GEM
22
21
  ffi-compiler (1.0.1)
23
22
  ffi (>= 1.0.0)
24
23
  rake
25
- git (1.11.0)
24
+ git (1.13.0)
25
+ addressable (~> 2.8)
26
26
  rchardet (~> 1.8)
27
27
  github_api (0.19.0)
28
28
  addressable (~> 2.4)
@@ -72,35 +72,37 @@ GEM
72
72
  minitest (5.16.2)
73
73
  minitest-focus (1.3.1)
74
74
  minitest (>= 4, < 6)
75
+ minitest-reporters (1.5.0)
76
+ ansi
77
+ builder
78
+ minitest (>= 5.0)
79
+ ruby-progressbar
75
80
  multi_json (1.15.0)
76
81
  multi_xml (0.6.0)
77
82
  multipart-post (2.1.1)
78
- nokogiri (1.13.9)
83
+ nokogiri (1.13.10)
79
84
  mini_portile2 (~> 2.8.0)
80
85
  racc (~> 1.4)
81
- oauth2 (1.4.7)
82
- faraday (>= 0.8, < 2.0)
86
+ oauth2 (1.4.11)
87
+ faraday (>= 0.17.3, < 3.0)
83
88
  jwt (>= 1.0, < 3.0)
84
89
  multi_json (~> 1.3)
85
90
  multi_xml (~> 0.5)
86
- rack (>= 1.2, < 3)
91
+ rack (>= 1.2, < 4)
87
92
  psych (3.3.1)
88
93
  public_suffix (4.0.6)
89
- racc (1.6.0)
90
- rack (2.2.4)
94
+ racc (1.6.1)
95
+ rack (3.0.4.1)
91
96
  rake (13.0.6)
92
97
  rchardet (1.8.0)
93
98
  rdoc (6.3.3)
99
+ ruby-progressbar (1.11.0)
94
100
  ruby2_keywords (0.0.4)
95
101
  semver2 (3.4.2)
96
102
  simplecov (0.18.5)
97
103
  docile (~> 1.1)
98
104
  simplecov-html (~> 0.11)
99
105
  simplecov-html (0.12.3)
100
- thin (1.8.1)
101
- daemons (~> 1.0, >= 1.0.9)
102
- eventmachine (~> 1.0, >= 1.0.4)
103
- rack (>= 1, < 3)
104
106
  thread_safe (0.3.6)
105
107
  unf (0.1.4)
106
108
  unf_ext
@@ -122,9 +124,9 @@ DEPENDENCIES
122
124
  ld-eventsource
123
125
  minitest
124
126
  minitest-focus
127
+ minitest-reporters
125
128
  rdoc
126
129
  simplecov
127
- thin
128
130
 
129
131
  BUNDLED WITH
130
132
  2.3.5
data/README.md CHANGED
@@ -41,7 +41,7 @@ end
41
41
  ```
42
42
 
43
43
  ## Logging & Debugging
44
- In classpath or ~/.prefab.overrides.config.yaml set
44
+ In classpath or ~/.prefab.default.config.yaml set
45
45
 
46
46
  ```
47
47
  log-level:
data/Rakefile CHANGED
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require 'rubygems'
@@ -6,21 +5,21 @@ require 'bundler'
6
5
  begin
7
6
  Bundler.setup(:default, :development)
8
7
  rescue Bundler::BundlerError => e
9
- $stderr.puts e.message
10
- $stderr.puts "Run `bundle install` to install missing gems"
8
+ warn e.message
9
+ warn 'Run `bundle install` to install missing gems'
11
10
  exit e.status_code
12
11
  end
13
12
  require 'rake'
14
13
  require 'juwelier'
15
14
  Juwelier::Tasks.new do |gem|
16
15
  # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
- gem.name = "prefab-cloud-ruby"
18
- gem.homepage = "http://github.com/prefab-cloud/prefab-cloud-ruby"
19
- gem.license = "MIT"
20
- gem.summary = %Q{Prefab Ruby Infrastructure}
21
- gem.description = %Q{RateLimits & Config as a service}
22
- gem.email = "jdwyer@prefab.cloud"
23
- gem.authors = ["Jeff Dwyer"]
16
+ gem.name = 'prefab-cloud-ruby'
17
+ gem.homepage = 'http://github.com/prefab-cloud/prefab-cloud-ruby'
18
+ gem.license = 'MIT'
19
+ gem.summary = %(Prefab Ruby Infrastructure)
20
+ gem.description = %(RateLimits & Config as a service)
21
+ gem.email = 'jdwyer@prefab.cloud'
22
+ gem.authors = ['Jeff Dwyer']
24
23
 
25
24
  # dependencies defined in Gemfile
26
25
  end
@@ -32,17 +31,17 @@ Rake::TestTask.new(:test) do |test|
32
31
  test.verbose = true
33
32
  end
34
33
 
35
- desc "Code coverage detail"
34
+ desc 'Code coverage detail'
36
35
  task :simplecov do
37
- ENV['COVERAGE'] = "true"
36
+ ENV['COVERAGE'] = 'true'
38
37
  Rake::Task['test'].execute
39
38
  end
40
39
 
41
- task :default => :test
40
+ task default: :test
42
41
 
43
42
  require 'rdoc/task'
44
43
  Rake::RDocTask.new do |rdoc|
45
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+ version = File.exist?('VERSION') ? File.read('VERSION') : ''
46
45
 
47
46
  rdoc.rdoc_dir = 'rdoc'
48
47
  rdoc.title = "prefab-cloud-ruby #{version}"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.20.0
1
+ 0.21.0
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class AuthInterceptor < GRPC::ClientInterceptor
4
- VERSION = File.exist?('VERSION') ? File.read('VERSION').chomp : ""
5
+ VERSION = File.exist?('VERSION') ? File.read('VERSION').chomp : ''
5
6
  CLIENT = "prefab-cloud-ruby.#{VERSION}".freeze
6
7
 
7
8
  def initialize(api_key)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class CancellableInterceptor < GRPC::ClientInterceptor
4
5
  WAIT_SEC = 3
@@ -8,20 +9,20 @@ module Prefab
8
9
  end
9
10
 
10
11
  def cancel
11
- @call.instance_variable_get("@wrapped").instance_variable_get("@call").cancel
12
+ @call.instance_variable_get('@wrapped').instance_variable_get('@call').cancel
12
13
  i = 0
13
- while (i < WAIT_SEC) do
14
- if @call.instance_variable_get("@wrapped").cancelled?
15
- @base_client.log_internal Logger::DEBUG, "Cancelled streaming."
14
+ while i < WAIT_SEC
15
+ if @call.instance_variable_get('@wrapped').cancelled?
16
+ @base_client.log_internal Logger::DEBUG, 'Cancelled streaming.'
16
17
  return
17
18
  else
18
- @base_client.log_internal Logger::DEBUG, "Unable to cancel streaming. Trying again"
19
- @call.instance_variable_get("@wrapped").instance_variable_get("@call").cancel
19
+ @base_client.log_internal Logger::DEBUG, 'Unable to cancel streaming. Trying again'
20
+ @call.instance_variable_get('@wrapped').instance_variable_get('@call').cancel
20
21
  i += 1
21
22
  sleep(1)
22
23
  end
23
24
  end
24
- @base_client.log_internal Logger::INFO, "Unable to cancel streaming."
25
+ @base_client.log_internal Logger::INFO, 'Unable to cancel streaming.'
25
26
  end
26
27
 
27
28
  def request_response(request:, call:, method:, metadata:, &block)
data/lib/prefab/client.rb CHANGED
@@ -1,11 +1,18 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class Client
4
5
  MAX_SLEEP_SEC = 10
5
6
  BASE_SLEEP_SEC = 0.5
6
7
  NO_DEFAULT_PROVIDED = :no_default_provided
7
8
 
8
- attr_reader :shared_cache, :stats, :namespace, :interceptor, :api_key, :prefab_api_url, :options
9
+ attr_reader :shared_cache
10
+ attr_reader :stats
11
+ attr_reader :namespace
12
+ attr_reader :interceptor
13
+ attr_reader :api_key
14
+ attr_reader :prefab_api_url
15
+ attr_reader :options
9
16
 
10
17
  def initialize(options = Prefab::Options.new)
11
18
  @options = options
@@ -15,14 +22,16 @@ module Prefab
15
22
  @stubs = {}
16
23
 
17
24
  if @options.local_only?
18
- log_internal Logger::INFO, "Prefab Running in Local Mode"
25
+ log_internal Logger::INFO, 'Prefab Running in Local Mode'
19
26
  else
20
27
  @api_key = @options.api_key
21
- raise Prefab::Errors::InvalidApiKeyError.new(@api_key) if @api_key.nil? || @api_key.empty? || api_key.count("-") < 1
28
+ raise Prefab::Errors::InvalidApiKeyError, @api_key if @api_key.nil? || @api_key.empty? || api_key.count('-') < 1
29
+
22
30
  @interceptor = Prefab::AuthInterceptor.new(@api_key)
23
31
  @prefab_api_url = @options.prefab_api_url
24
32
  @prefab_grpc_url = @options.prefab_grpc_url
25
- log_internal Logger::INFO, "Prefab Connecting to: #{@prefab_api_url} and #{@prefab_grpc_url} Secure: #{http_secure?}"
33
+ log_internal Logger::INFO,
34
+ "Prefab Connecting to: #{@prefab_api_url} and #{@prefab_grpc_url} Secure: #{http_secure?}"
26
35
  at_exit do
27
36
  channel.destroy
28
37
  end
@@ -63,16 +72,14 @@ module Prefab
63
72
 
64
73
  begin
65
74
  attempts += 1
66
- return stub_for(service, opts[:timeout]).send(method, *params)
67
- rescue => exception
75
+ stub_for(service, opts[:timeout]).send(method, *params)
76
+ rescue StandardError => e
77
+ log_internal Logger::WARN, e
68
78
 
69
- log_internal Logger::WARN, exception
79
+ raise e if Time.now - start_time > opts[:timeout]
70
80
 
71
- if Time.now - start_time > opts[:timeout]
72
- raise exception
73
- end
74
- sleep_seconds = [BASE_SLEEP_SEC * (2 ** (attempts - 1)), MAX_SLEEP_SEC].min
75
- sleep_seconds = sleep_seconds * (0.5 * (1 + rand()))
81
+ sleep_seconds = [BASE_SLEEP_SEC * (2**(attempts - 1)), MAX_SLEEP_SEC].min
82
+ sleep_seconds *= (0.5 * (1 + rand))
76
83
  sleep_seconds = [BASE_SLEEP_SEC, sleep_seconds].max
77
84
  log_internal Logger::INFO, "Sleep #{sleep_seconds} and Reset #{service} #{method}"
78
85
  sleep sleep_seconds
@@ -86,24 +93,28 @@ module Prefab
86
93
  @_channel = nil
87
94
  end
88
95
 
89
- def enabled?(feature_name, lookup_key=nil, attributes={})
96
+ def enabled?(feature_name, lookup_key = nil, attributes = {})
90
97
  feature_flag_client.feature_is_on_for?(feature_name, lookup_key, attributes: attributes)
91
98
  end
92
99
 
93
- def get(key, default_or_lookup_key=NO_DEFAULT_PROVIDED, attributes={}, ff_default=NO_DEFAULT_PROVIDED)
94
- result = config_client.get(key, default_or_lookup_key)
95
-
96
- if result.is_a?(Prefab::FeatureFlag)
97
- feature_flag_client.get(key, default_or_lookup_key, attributes, default: ff_default)
100
+ def get(key, default_or_lookup_key = NO_DEFAULT_PROVIDED, properties = {}, ff_default = nil)
101
+ if is_ff?(key)
102
+ feature_flag_client.get(key, default_or_lookup_key, properties, default: ff_default)
98
103
  else
99
- result
104
+ config_client.get(key, default_or_lookup_key, properties)
100
105
  end
101
106
  end
102
107
 
103
108
  private
104
109
 
110
+ def is_ff?(key)
111
+ raw = config_client.send(:raw, key)
112
+
113
+ raw && raw.allowable_values.any?
114
+ end
115
+
105
116
  def http_secure?
106
- ENV["PREFAB_CLOUD_HTTP"] != "true"
117
+ ENV['PREFAB_CLOUD_HTTP'] != 'true'
107
118
  end
108
119
 
109
120
  def stub_for(service, timeout)
@@ -119,7 +130,7 @@ module Prefab
119
130
  end
120
131
 
121
132
  def ssl_certs
122
- ssl_certs = ""
133
+ ssl_certs = ''
123
134
  Dir["#{OpenSSL::X509::DEFAULT_CERT_DIR}/*.pem"].each do |cert|
124
135
  ssl_certs += File.open(cert).read
125
136
  end
@@ -127,11 +138,9 @@ module Prefab
127
138
  ssl_certs += File.open(OpenSSL::X509::DEFAULT_CERT_FILE).read
128
139
  end
129
140
  ssl_certs
130
- rescue => e
141
+ rescue StandardError => e
131
142
  log.warn("Issue loading SSL certs #{e.message}")
132
143
  ssl_certs
133
144
  end
134
-
135
145
  end
136
146
  end
137
-
@@ -1,17 +1,16 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Prefab
3
4
  class ConfigClient
4
- include Prefab::ConfigHelper
5
-
6
5
  RECONNECT_WAIT = 5
7
6
  DEFAULT_CHECKPOINT_FREQ_SEC = 60
8
7
  SSE_READ_TIMEOUT = 300
9
- AUTH_USER = "authuser"
8
+ AUTH_USER = 'authuser'
10
9
 
11
10
  def initialize(base_client, timeout)
12
11
  @base_client = base_client
13
12
  @options = base_client.options
14
- @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient"
13
+ @base_client.log_internal Logger::DEBUG, 'Initialize ConfigClient'
15
14
  @timeout = timeout
16
15
 
17
16
  @stream_lock = Concurrent::ReadWriteLock.new
@@ -22,9 +21,9 @@ module Prefab
22
21
  @config_resolver = Prefab::ConfigResolver.new(@base_client, @config_loader)
23
22
 
24
23
  @initialization_lock = Concurrent::ReadWriteLock.new
25
- @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient: AcquireWriteLock"
24
+ @base_client.log_internal Logger::DEBUG, 'Initialize ConfigClient: AcquireWriteLock'
26
25
  @initialization_lock.acquire_write_lock
27
- @base_client.log_internal Logger::DEBUG, "Initialize ConfigClient: AcquiredWriteLock"
26
+ @base_client.log_internal Logger::DEBUG, 'Initialize ConfigClient: AcquiredWriteLock'
28
27
  @initialized_future = Concurrent::Future.execute { @initialization_lock.acquire_read_lock }
29
28
 
30
29
  @cancellable_interceptor = Prefab::CancellableInterceptor.new(@base_client)
@@ -45,14 +44,15 @@ module Prefab
45
44
  end
46
45
 
47
46
  def upsert(key, config_value, namespace = nil, previous_key = nil)
48
- raise "Key must not contain ':' set namespaces separately" if key.include? ":"
49
- raise "Namespace must not contain ':'" if namespace&.include?(":")
47
+ raise "Key must not contain ':' set namespaces separately" if key.include? ':'
48
+ raise "Namespace must not contain ':'" if namespace&.include?(':')
49
+
50
50
  config_delta = Prefab::ConfigClient.value_to_delta(key, config_value, namespace)
51
51
  upsert_req = Prefab::UpsertRequest.new(config_delta: config_delta)
52
52
  upsert_req.previous_key = previous_key if previous_key&.present?
53
53
 
54
54
  @base_client.request Prefab::ConfigService, :upsert, req_options: { timeout: @timeout }, params: upsert_req
55
- @base_client.stats.increment("prefab.config.upsert")
55
+ @base_client.stats.increment('prefab.config.upsert')
56
56
  @config_loader.set(config_delta, :upsert)
57
57
  @config_loader.rm(previous_key) if previous_key&.present?
58
58
  @config_resolver.update
@@ -68,46 +68,43 @@ module Prefab
68
68
  end
69
69
 
70
70
  def self.value_to_delta(key, config_value, namespace = nil)
71
- Prefab::Config.new(key: [namespace, key].compact.join(":"),
71
+ Prefab::Config.new(key: [namespace, key].compact.join(':'),
72
72
  rows: [Prefab::ConfigRow.new(value: config_value)])
73
73
  end
74
74
 
75
- def get(key, default=Prefab::Client::NO_DEFAULT_PROVIDED)
76
- config = _get(key)
77
- config ? value_of(config[:value]) : handle_default(key, default)
78
- end
79
-
80
- def get_config_obj(key)
81
- config = _get(key)
82
- config ? config[:config] : nil
75
+ def get(key, default = Prefab::Client::NO_DEFAULT_PROVIDED, properties = {}, lookup_key = nil)
76
+ value = _get(key, lookup_key, properties)
77
+ value ? Prefab::ConfigValueUnwrapper.unwrap(value, key, properties) : handle_default(key, default)
83
78
  end
84
79
 
85
80
  private
86
81
 
82
+ def raw(key)
83
+ @config_resolver.raw(key)
84
+ end
85
+
87
86
  def handle_default(key, default)
88
- if default != Prefab::Client::NO_DEFAULT_PROVIDED
89
- return default
90
- end
87
+ return default if default != Prefab::Client::NO_DEFAULT_PROVIDED
91
88
 
92
- if @options.on_no_default == Prefab::Options::ON_NO_DEFAULT::RAISE
93
- raise Prefab::Errors::MissingDefaultError.new(key)
94
- end
89
+ raise Prefab::Errors::MissingDefaultError, key if @options.on_no_default == Prefab::Options::ON_NO_DEFAULT::RAISE
95
90
 
96
91
  nil
97
92
  end
98
93
 
99
- def _get(key)
94
+ def _get(key, lookup_key, properties)
100
95
  # wait timeout sec for the initalization to be complete
101
96
  @initialized_future.value(@options.initialization_timeout_sec)
102
97
  if @initialized_future.incomplete?
103
- if @options.on_init_failure == Prefab::Options::ON_INITIALIZATION_FAILURE::RETURN
104
- @base_client.log_internal Logger::WARN, "Couldn't Initialize In #{@options.initialization_timeout_sec}. Key #{key}. Returning what we have"
105
- @initialization_lock.release_write_lock
106
- else
98
+ unless @options.on_init_failure == Prefab::Options::ON_INITIALIZATION_FAILURE::RETURN
107
99
  raise Prefab::Errors::InitializationTimeoutError.new(@options.initialization_timeout_sec, key)
108
100
  end
101
+
102
+ @base_client.log_internal Logger::WARN,
103
+ "Couldn't Initialize In #{@options.initialization_timeout_sec}. Key #{key}. Returning what we have"
104
+ @initialization_lock.release_write_lock
105
+
109
106
  end
110
- @config_resolver._get(key)
107
+ @config_resolver.get(key, lookup_key, properties)
111
108
  end
112
109
 
113
110
  def stub
@@ -120,19 +117,15 @@ module Prefab
120
117
  def load_checkpoint
121
118
  success = load_checkpoint_api_cdn
122
119
 
123
- if success
124
- return
125
- else
126
- @base_client.log_internal Logger::INFO, "LoadCheckpoint: Fallback to GRPC API"
127
- end
120
+ return if success
121
+
122
+ @base_client.log_internal Logger::INFO, 'LoadCheckpoint: Fallback to GRPC API'
128
123
 
129
124
  success = load_checkpoint_from_grpc_api
130
125
 
131
- if success
132
- return
133
- else
134
- @base_client.log_internal Logger::WARN, "No success loading checkpoints"
135
- end
126
+ return if success
127
+
128
+ @base_client.log_internal Logger::WARN, 'No success loading checkpoints'
136
129
  end
137
130
 
138
131
  def load_checkpoint_from_grpc_api
@@ -142,8 +135,8 @@ module Prefab
142
135
  load_configs(resp, :remote_api_grpc)
143
136
  true
144
137
  rescue GRPC::Unauthenticated
145
- @base_client.log_internal Logger::WARN, "Unauthenticated"
146
- rescue => e
138
+ @base_client.log_internal Logger::WARN, 'Unauthenticated'
139
+ rescue StandardError => e
147
140
  @base_client.log_internal Logger::WARN, "Unexpected grpc_api problem loading checkpoint #{e}"
148
141
  false
149
142
  end
@@ -172,7 +165,7 @@ module Prefab
172
165
  @base_client.log_internal Logger::INFO, "Checkpoint #{source} failed to load. Response #{resp.status}"
173
166
  false
174
167
  end
175
- rescue => e
168
+ rescue StandardError => e
176
169
  @base_client.log_internal Logger::WARN, "Unexpected #{source} problem loading checkpoint #{e} #{conn}"
177
170
  false
178
171
  end
@@ -187,42 +180,39 @@ module Prefab
187
180
  @config_loader.set(config, source)
188
181
  end
189
182
  if @config_loader.highwater_mark > starting_highwater_mark
190
- @base_client.log_internal Logger::INFO, "Found new checkpoint with highwater id #{@config_loader.highwater_mark} from #{source} in project #{project_id} environment: #{project_env_id} and namespace: '#{@namespace}'"
183
+ @base_client.log_internal Logger::INFO,
184
+ "Found new checkpoint with highwater id #{@config_loader.highwater_mark} from #{source} in project #{project_id} environment: #{project_env_id} and namespace: '#{@namespace}'"
191
185
  else
192
- @base_client.log_internal Logger::DEBUG, "Checkpoint with highwater id #{@config_loader.highwater_mark} from #{source}. No changes.", "load_configs"
186
+ @base_client.log_internal Logger::DEBUG,
187
+ "Checkpoint with highwater id #{@config_loader.highwater_mark} from #{source}. No changes.", 'load_configs'
193
188
  end
194
- @base_client.stats.increment("prefab.config.checkpoint.load")
189
+ @base_client.stats.increment('prefab.config.checkpoint.load')
195
190
  @config_resolver.update
196
191
  finish_init!(source)
197
192
  end
198
193
 
199
194
  # A thread that checks for a checkpoint
200
195
  def start_checkpointing_thread
201
-
202
196
  Thread.new do
203
197
  loop do
204
- begin
205
- load_checkpoint
206
-
207
- started_at = Time.now
208
- delta = @checkpoint_freq_secs - (Time.now - started_at)
209
- if delta > 0
210
- sleep(delta)
211
- end
212
- rescue StandardError => exn
213
- @base_client.log_internal Logger::INFO, "Issue Checkpointing #{exn.message}"
214
- end
198
+ load_checkpoint
199
+
200
+ started_at = Time.now
201
+ delta = @checkpoint_freq_secs - (Time.now - started_at)
202
+ sleep(delta) if delta > 0
203
+ rescue StandardError => e
204
+ @base_client.log_internal Logger::INFO, "Issue Checkpointing #{e.message}"
215
205
  end
216
206
  end
217
207
  end
218
208
 
219
209
  def finish_init!(source)
220
- if @initialization_lock.write_locked?
221
- @base_client.log_internal Logger::INFO, "Unlocked Config via #{source}"
222
- @initialization_lock.release_write_lock
223
- @base_client.log.set_config_client(self)
224
- @base_client.log_internal Logger::INFO, to_s
225
- end
210
+ return unless @initialization_lock.write_locked?
211
+
212
+ @base_client.log_internal Logger::INFO, "Unlocked Config via #{source}"
213
+ @initialization_lock.release_write_lock
214
+ @base_client.log.set_config_client(self)
215
+ @base_client.log_internal Logger::INFO, to_s
226
216
  end
227
217
 
228
218
  def start_sse_streaming_connection_thread(start_at_id)
@@ -230,7 +220,7 @@ module Prefab
230
220
  auth_string = Base64.strict_encode64(auth)
231
221
  headers = {
232
222
  "x-prefab-start-at-id": start_at_id,
233
- "Authorization": "Basic #{auth_string}",
223
+ "Authorization": "Basic #{auth_string}"
234
224
  }
235
225
  url = "#{@base_client.prefab_api_url}/api/v1/sse/config"
236
226
  @base_client.log_internal Logger::INFO, "SSE Streaming Connect to #{url} start_at #{start_at_id}"
@@ -246,4 +236,3 @@ module Prefab
246
236
  end
247
237
  end
248
238
  end
249
-