prefab-cloud-ruby 0.20.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
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
-