prefab-cloud-ruby 0.23.3 → 0.23.4
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/Gemfile +0 -2
- data/Gemfile.lock +0 -6
- data/README.md +1 -3
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/prefab/client.rb +5 -79
- data/lib/prefab/config_client.rb +7 -40
- data/lib/prefab/http_connection.rb +37 -0
- data/lib/prefab/log_path_collector.rb +1 -1
- data/lib/prefab/options.rb +0 -3
- data/lib/prefab-cloud-ruby.rb +1 -4
- data/prefab-cloud-ruby.gemspec +5 -11
- data/test/integration_test.rb +1 -2
- data/test/test_client.rb +0 -7
- data/test/test_log_path_collector.rb +21 -15
- metadata +4 -34
- data/lib/prefab/auth_interceptor.rb +0 -34
- data/lib/prefab/cancellable_interceptor.rb +0 -49
- data/lib/prefab/ratelimit_client.rb +0 -78
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74e19eed1d40cad8e3ea9b99a8755c90864a97b4a00e08d2df6a9fe5226f5ad0
|
4
|
+
data.tar.gz: 4ad94565a39139d01795007077128d8f997c05e6a8b785e019ca8b66308df5c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a10679fe049175ebaf01f12194f91bea1a98ce226bf0e0f3e87aea3ab299c888fb7cebfe67b942e77dc46367c9b05cc5acaf995870e1d6ee1f2b8aa744f2fa3
|
7
|
+
data.tar.gz: c6e506da285ae5f7913f81891e7f32a1b5365f1071bc90323f317aa2523fddb0bd41c2d8a53decf2afec000e234d535713e198f3ac8b4c98259c7904f03ce7ad
|
data/Gemfile
CHANGED
@@ -4,14 +4,12 @@ gem 'concurrent-ruby', '~> 1.0', '>= 1.0.5'
|
|
4
4
|
gem 'faraday'
|
5
5
|
gem 'googleapis-common-protos-types', platforms: :ruby
|
6
6
|
gem 'google-protobuf', platforms: :ruby
|
7
|
-
gem 'grpc', platforms: :ruby
|
8
7
|
gem 'ld-eventsource'
|
9
8
|
gem 'uuid'
|
10
9
|
|
11
10
|
group :development do
|
12
11
|
gem 'benchmark-ips'
|
13
12
|
gem 'bundler'
|
14
|
-
gem 'grpc-tools', platforms: :ruby
|
15
13
|
gem 'juwelier', '~> 2.4.9'
|
16
14
|
gem 'rdoc'
|
17
15
|
gem 'simplecov', '>= 0'
|
data/Gemfile.lock
CHANGED
@@ -33,10 +33,6 @@ GEM
|
|
33
33
|
google-protobuf (3.22.2)
|
34
34
|
googleapis-common-protos-types (1.5.0)
|
35
35
|
google-protobuf (~> 3.14)
|
36
|
-
grpc (1.53.0)
|
37
|
-
google-protobuf (~> 3.21)
|
38
|
-
googleapis-common-protos-types (~> 1.0)
|
39
|
-
grpc-tools (1.43.1)
|
40
36
|
hashie (3.6.0)
|
41
37
|
highline (2.0.3)
|
42
38
|
http (5.0.1)
|
@@ -124,8 +120,6 @@ DEPENDENCIES
|
|
124
120
|
faraday
|
125
121
|
google-protobuf
|
126
122
|
googleapis-common-protos-types
|
127
|
-
grpc
|
128
|
-
grpc-tools
|
129
123
|
juwelier (~> 2.4.9)
|
130
124
|
ld-eventsource
|
131
125
|
minitest
|
data/README.md
CHANGED
@@ -28,9 +28,7 @@ See full documentation https://docs.prefab.cloud/docs/ruby-sdk/ruby
|
|
28
28
|
|
29
29
|
## Important note about Forking and realtime updates
|
30
30
|
|
31
|
-
Many ruby web servers fork.
|
32
|
-
|
33
|
-
If you're using Puma or Unicorn, you can do the following.
|
31
|
+
Many ruby web servers fork. When the process is forked, the current realtime update stream is disconnected. If you're using Puma or Unicorn, do the following.
|
34
32
|
|
35
33
|
```ruby
|
36
34
|
#config/initializers/prefab.rb
|
data/Rakefile
CHANGED
@@ -17,7 +17,7 @@ Juwelier::Tasks.new do |gem|
|
|
17
17
|
gem.homepage = 'http://github.com/prefab-cloud/prefab-cloud-ruby'
|
18
18
|
gem.license = 'MIT'
|
19
19
|
gem.summary = %(Prefab Ruby Infrastructure)
|
20
|
-
gem.description = %(
|
20
|
+
gem.description = %(Feature Flags, Live Config, and Dynamic Log Levels as a service)
|
21
21
|
gem.email = 'jdwyer@prefab.cloud'
|
22
22
|
gem.authors = ['Jeff Dwyer']
|
23
23
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.23.
|
1
|
+
0.23.4
|
data/lib/prefab/client.rb
CHANGED
@@ -31,14 +31,8 @@ module Prefab
|
|
31
31
|
@api_key = @options.api_key
|
32
32
|
raise Prefab::Errors::InvalidApiKeyError, @api_key if @api_key.nil? || @api_key.empty? || api_key.count('-') < 1
|
33
33
|
|
34
|
-
@interceptor = Prefab::AuthInterceptor.new(@api_key)
|
35
34
|
@prefab_api_url = @options.prefab_api_url
|
36
|
-
|
37
|
-
log_internal ::Logger::INFO,
|
38
|
-
"Prefab Connecting to: #{@prefab_api_url} and #{@prefab_grpc_url} Secure: #{http_secure?}"
|
39
|
-
at_exit do
|
40
|
-
channel.destroy
|
41
|
-
end
|
35
|
+
log_internal ::Logger::INFO, "Prefab Connecting to: #{@prefab_api_url}"
|
42
36
|
end
|
43
37
|
# start config client
|
44
38
|
config_client
|
@@ -54,19 +48,10 @@ module Prefab
|
|
54
48
|
Thread.current[:prefab_log_properties] = {}
|
55
49
|
end
|
56
50
|
|
57
|
-
def channel
|
58
|
-
credentials = http_secure? ? creds : :this_channel_is_insecure
|
59
|
-
@_channel ||= GRPC::Core::Channel.new(@prefab_grpc_url, nil, credentials)
|
60
|
-
end
|
61
|
-
|
62
51
|
def config_client(timeout: 5.0)
|
63
52
|
@config_client ||= Prefab::ConfigClient.new(self, timeout)
|
64
53
|
end
|
65
54
|
|
66
|
-
def ratelimit_client(timeout: 5.0)
|
67
|
-
@ratelimit_client ||= Prefab::RateLimitClient.new(self, timeout)
|
68
|
-
end
|
69
|
-
|
70
55
|
def feature_flag_client
|
71
56
|
@feature_flag_client ||= Prefab::FeatureFlagClient.new(self)
|
72
57
|
end
|
@@ -97,39 +82,6 @@ module Prefab
|
|
97
82
|
log.log_internal msg, path, nil, level
|
98
83
|
end
|
99
84
|
|
100
|
-
def request(service, method, req_options: {}, params: {})
|
101
|
-
# Future-proofing since we previously bumped into a conflict with a service with a `send` method
|
102
|
-
raise ArgumentError, 'Cannot call public_send on an grpc service in Ruby' if method.to_s == 'public_send'
|
103
|
-
|
104
|
-
opts = { timeout: 10 }.merge(req_options)
|
105
|
-
|
106
|
-
attempts = 0
|
107
|
-
start_time = Time.now
|
108
|
-
|
109
|
-
begin
|
110
|
-
attempts += 1
|
111
|
-
|
112
|
-
stub_for(service, opts[:timeout]).public_send(method, *params)
|
113
|
-
rescue StandardError => e
|
114
|
-
log_internal ::Logger::WARN, e
|
115
|
-
|
116
|
-
raise e if Time.now - start_time > opts[:timeout]
|
117
|
-
|
118
|
-
sleep_seconds = [BASE_SLEEP_SEC * (2**(attempts - 1)), MAX_SLEEP_SEC].min
|
119
|
-
sleep_seconds *= (0.5 * (1 + rand))
|
120
|
-
sleep_seconds = [BASE_SLEEP_SEC, sleep_seconds].max
|
121
|
-
log_internal ::Logger::INFO, "Sleep #{sleep_seconds} and Reset #{service} #{method}"
|
122
|
-
sleep sleep_seconds
|
123
|
-
reset!
|
124
|
-
retry
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def reset!
|
129
|
-
@stubs.clear
|
130
|
-
@_channel = nil
|
131
|
-
end
|
132
|
-
|
133
85
|
def enabled?(feature_name, lookup_key = nil, attributes = {})
|
134
86
|
feature_flag_client.feature_is_on_for?(feature_name, lookup_key, attributes: attributes)
|
135
87
|
end
|
@@ -142,6 +94,10 @@ module Prefab
|
|
142
94
|
end
|
143
95
|
end
|
144
96
|
|
97
|
+
def post(path, body)
|
98
|
+
Prefab::HttpConnection.new(@options.prefab_api_url, @api_key).post(path, body)
|
99
|
+
end
|
100
|
+
|
145
101
|
private
|
146
102
|
|
147
103
|
def is_ff?(key)
|
@@ -149,35 +105,5 @@ module Prefab
|
|
149
105
|
|
150
106
|
raw && raw.allowable_values.any?
|
151
107
|
end
|
152
|
-
|
153
|
-
def http_secure?
|
154
|
-
ENV['PREFAB_CLOUD_HTTP'] != 'true'
|
155
|
-
end
|
156
|
-
|
157
|
-
def stub_for(service, timeout)
|
158
|
-
@stubs["#{service}_#{timeout}"] ||= service::Stub.new(nil,
|
159
|
-
nil,
|
160
|
-
timeout: timeout,
|
161
|
-
channel_override: channel,
|
162
|
-
interceptors: [@interceptor])
|
163
|
-
end
|
164
|
-
|
165
|
-
def creds
|
166
|
-
GRPC::Core::ChannelCredentials.new(ssl_certs)
|
167
|
-
end
|
168
|
-
|
169
|
-
def ssl_certs
|
170
|
-
ssl_certs = ''
|
171
|
-
Dir["#{OpenSSL::X509::DEFAULT_CERT_DIR}/*.pem"].each do |cert|
|
172
|
-
ssl_certs += File.open(cert).read
|
173
|
-
end
|
174
|
-
if OpenSSL::X509::DEFAULT_CERT_FILE && File.exist?(OpenSSL::X509::DEFAULT_CERT_FILE)
|
175
|
-
ssl_certs += File.open(OpenSSL::X509::DEFAULT_CERT_FILE).read
|
176
|
-
end
|
177
|
-
ssl_certs
|
178
|
-
rescue StandardError => e
|
179
|
-
log.warn("Issue loading SSL certs #{e.message}")
|
180
|
-
ssl_certs
|
181
|
-
end
|
182
108
|
end
|
183
109
|
end
|
data/lib/prefab/config_client.rb
CHANGED
@@ -26,8 +26,6 @@ module Prefab
|
|
26
26
|
@base_client.log_internal ::Logger::DEBUG, 'Initialize ConfigClient: AcquiredWriteLock'
|
27
27
|
@initialized_future = Concurrent::Future.execute { @initialization_lock.acquire_read_lock }
|
28
28
|
|
29
|
-
@cancellable_interceptor = Prefab::CancellableInterceptor.new(@base_client)
|
30
|
-
|
31
29
|
if @options.local_only?
|
32
30
|
finish_init!(:local_only)
|
33
31
|
else
|
@@ -58,11 +56,6 @@ module Prefab
|
|
58
56
|
@config_resolver.update
|
59
57
|
end
|
60
58
|
|
61
|
-
def reset
|
62
|
-
@base_client.reset!
|
63
|
-
@_stub = nil
|
64
|
-
end
|
65
|
-
|
66
59
|
def to_s
|
67
60
|
@config_resolver.to_s
|
68
61
|
end
|
@@ -108,54 +101,28 @@ module Prefab
|
|
108
101
|
@config_resolver.get(key, lookup_key, properties)
|
109
102
|
end
|
110
103
|
|
111
|
-
def stub
|
112
|
-
@_stub = Prefab::ConfigService::Stub.new(nil,
|
113
|
-
nil,
|
114
|
-
channel_override: @base_client.channel,
|
115
|
-
interceptors: [@base_client.interceptor, @cancellable_interceptor])
|
116
|
-
end
|
117
|
-
|
118
104
|
def load_checkpoint
|
119
105
|
success = load_checkpoint_api_cdn
|
120
106
|
|
121
107
|
return if success
|
122
108
|
|
123
|
-
|
124
|
-
|
125
|
-
success = load_checkpoint_from_grpc_api
|
109
|
+
success = load_checkpoint_api
|
126
110
|
|
127
111
|
return if success
|
128
112
|
|
129
113
|
@base_client.log_internal ::Logger::WARN, 'No success loading checkpoints'
|
130
114
|
end
|
131
115
|
|
132
|
-
def load_checkpoint_from_grpc_api
|
133
|
-
config_req = Prefab::ConfigServicePointer.new(start_at_id: @config_loader.highwater_mark)
|
134
|
-
|
135
|
-
resp = stub.get_all_config(config_req)
|
136
|
-
load_configs(resp, :remote_api_grpc)
|
137
|
-
true
|
138
|
-
rescue GRPC::Unauthenticated
|
139
|
-
@base_client.log_internal ::Logger::WARN, 'Unauthenticated'
|
140
|
-
rescue StandardError => e
|
141
|
-
@base_client.log_internal ::Logger::WARN, "Unexpected grpc_api problem loading checkpoint #{e}"
|
142
|
-
false
|
143
|
-
end
|
144
|
-
|
145
116
|
def load_checkpoint_api_cdn
|
146
|
-
|
147
|
-
conn = if Faraday::VERSION[0].to_i >= 2
|
148
|
-
Faraday.new(url) do |conn|
|
149
|
-
conn.request :authorization, :basic, AUTH_USER, @base_client.api_key
|
150
|
-
end
|
151
|
-
else
|
152
|
-
Faraday.new(url) do |conn|
|
153
|
-
conn.request :basic_auth, AUTH_USER, @base_client.api_key
|
154
|
-
end
|
155
|
-
end
|
117
|
+
conn = Prefab::HttpConnection.new("#{@options.url_for_api_cdn}/api/v1/configs/0", @base_client.api_key)
|
156
118
|
load_url(conn, :remote_cdn_api)
|
157
119
|
end
|
158
120
|
|
121
|
+
def load_checkpoint_api
|
122
|
+
conn = Prefab::HttpConnection.new("#{@options.prefab_api_url}/api/v1/configs/0", @base_client.api_key)
|
123
|
+
load_url(conn, :remote_api)
|
124
|
+
end
|
125
|
+
|
159
126
|
def load_url(conn, source)
|
160
127
|
resp = conn.get('')
|
161
128
|
if resp.status == 200
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prefab
|
4
|
+
class HttpConnection
|
5
|
+
AUTH_USER = 'authuser'
|
6
|
+
PROTO_HEADERS = { 'Content-Type' => 'application/x-protobuf', 'Accept' => 'application/x-protobuf' }.freeze
|
7
|
+
|
8
|
+
def initialize(api_root, api_key)
|
9
|
+
@api_root = api_root
|
10
|
+
@api_key = api_key
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(path)
|
14
|
+
connection.get(path)
|
15
|
+
end
|
16
|
+
|
17
|
+
def post(path, body)
|
18
|
+
connection(PROTO_HEADERS).post(path, body.to_proto)
|
19
|
+
end
|
20
|
+
|
21
|
+
def connection(headers = {})
|
22
|
+
if Faraday::VERSION[0].to_i >= 2
|
23
|
+
Faraday.new(@api_root) do |conn|
|
24
|
+
conn.request :authorization, :basic, AUTH_USER, @api_key
|
25
|
+
|
26
|
+
conn.headers.merge!(headers)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
Faraday.new(@api_root) do |conn|
|
30
|
+
conn.request :basic_auth, AUTH_USER, @api_key
|
31
|
+
|
32
|
+
conn.headers.merge!(headers)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/prefab/options.rb
CHANGED
@@ -10,7 +10,6 @@ module Prefab
|
|
10
10
|
attr_reader :shared_cache
|
11
11
|
attr_reader :namespace
|
12
12
|
attr_reader :prefab_api_url
|
13
|
-
attr_reader :prefab_grpc_url
|
14
13
|
attr_reader :on_no_default
|
15
14
|
attr_reader :initialization_timeout_sec
|
16
15
|
attr_reader :on_init_failure
|
@@ -49,7 +48,6 @@ module Prefab
|
|
49
48
|
log_formatter: DEFAULT_LOG_FORMATTER,
|
50
49
|
log_prefix: nil,
|
51
50
|
prefab_api_url: ENV['PREFAB_API_URL'] || 'https://api.prefab.cloud',
|
52
|
-
prefab_grpc_url: ENV['PREFAB_GRPC_URL'] || 'grpc.prefab.cloud:443',
|
53
51
|
on_no_default: ON_NO_DEFAULT::RAISE, # options :raise, :warn_and_return_nil,
|
54
52
|
initialization_timeout_sec: 10, # how long to wait before on_init_failure
|
55
53
|
on_init_failure: ON_INITIALIZATION_FAILURE::RAISE, # options :unlock_and_continue, :lock_and_keep_trying, :raise
|
@@ -71,7 +69,6 @@ module Prefab
|
|
71
69
|
@log_formatter = log_formatter
|
72
70
|
@log_prefix = log_prefix
|
73
71
|
@prefab_api_url = remove_trailing_slash(prefab_api_url)
|
74
|
-
@prefab_grpc_url = prefab_grpc_url
|
75
72
|
@on_no_default = on_no_default
|
76
73
|
@initialization_timeout_sec = initialization_timeout_sec
|
77
74
|
@on_init_failure = on_init_failure
|
data/lib/prefab-cloud-ruby.rb
CHANGED
@@ -12,7 +12,6 @@ require 'prefab/exponential_backoff'
|
|
12
12
|
require 'prefab/errors/initialization_timeout_error'
|
13
13
|
require 'prefab/errors/invalid_api_key_error'
|
14
14
|
require 'prefab/errors/missing_default_error'
|
15
|
-
require 'prefab_services_pb'
|
16
15
|
require 'prefab/options'
|
17
16
|
require 'prefab/internal_logger'
|
18
17
|
require 'prefab/sse_logger'
|
@@ -23,13 +22,11 @@ require 'prefab/config_loader'
|
|
23
22
|
require 'prefab/local_config_parser'
|
24
23
|
require 'prefab/yaml_config_parser'
|
25
24
|
require 'prefab/config_resolver'
|
25
|
+
require 'prefab/http_connection'
|
26
26
|
require 'prefab/client'
|
27
|
-
require 'prefab/ratelimit_client'
|
28
27
|
require 'prefab/config_client'
|
29
28
|
require 'prefab/feature_flag_client'
|
30
29
|
require 'prefab/logger_client'
|
31
|
-
require 'prefab/auth_interceptor'
|
32
|
-
require 'prefab/cancellable_interceptor'
|
33
30
|
require 'prefab/noop_cache'
|
34
31
|
require 'prefab/noop_stats'
|
35
32
|
require 'prefab/murmer3'
|
data/prefab-cloud-ruby.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: prefab-cloud-ruby 0.23.
|
5
|
+
# stub: prefab-cloud-ruby 0.23.4 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "prefab-cloud-ruby".freeze
|
9
|
-
s.version = "0.23.
|
9
|
+
s.version = "0.23.4"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Jeff Dwyer".freeze]
|
14
|
-
s.date = "2023-04-
|
15
|
-
s.description = "
|
14
|
+
s.date = "2023-04-12"
|
15
|
+
s.description = "Feature Flags, Live Config, and Dynamic Log Levels as a service".freeze
|
16
16
|
s.email = "jdwyer@prefab.cloud".freeze
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"LICENSE.txt",
|
@@ -33,8 +33,6 @@ Gem::Specification.new do |s|
|
|
33
33
|
"VERSION",
|
34
34
|
"compile_protos.sh",
|
35
35
|
"lib/prefab-cloud-ruby.rb",
|
36
|
-
"lib/prefab/auth_interceptor.rb",
|
37
|
-
"lib/prefab/cancellable_interceptor.rb",
|
38
36
|
"lib/prefab/client.rb",
|
39
37
|
"lib/prefab/config_client.rb",
|
40
38
|
"lib/prefab/config_loader.rb",
|
@@ -47,6 +45,7 @@ Gem::Specification.new do |s|
|
|
47
45
|
"lib/prefab/errors/missing_default_error.rb",
|
48
46
|
"lib/prefab/exponential_backoff.rb",
|
49
47
|
"lib/prefab/feature_flag_client.rb",
|
48
|
+
"lib/prefab/http_connection.rb",
|
50
49
|
"lib/prefab/internal_logger.rb",
|
51
50
|
"lib/prefab/local_config_parser.rb",
|
52
51
|
"lib/prefab/log_path_collector.rb",
|
@@ -55,7 +54,6 @@ Gem::Specification.new do |s|
|
|
55
54
|
"lib/prefab/noop_cache.rb",
|
56
55
|
"lib/prefab/noop_stats.rb",
|
57
56
|
"lib/prefab/options.rb",
|
58
|
-
"lib/prefab/ratelimit_client.rb",
|
59
57
|
"lib/prefab/sse_logger.rb",
|
60
58
|
"lib/prefab/weighted_value_resolver.rb",
|
61
59
|
"lib/prefab/yaml_config_parser.rb",
|
@@ -96,12 +94,10 @@ Gem::Specification.new do |s|
|
|
96
94
|
s.add_runtime_dependency(%q<faraday>.freeze, [">= 0"])
|
97
95
|
s.add_runtime_dependency(%q<googleapis-common-protos-types>.freeze, [">= 0"])
|
98
96
|
s.add_runtime_dependency(%q<google-protobuf>.freeze, [">= 0"])
|
99
|
-
s.add_runtime_dependency(%q<grpc>.freeze, [">= 0"])
|
100
97
|
s.add_runtime_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
101
98
|
s.add_runtime_dependency(%q<uuid>.freeze, [">= 0"])
|
102
99
|
s.add_development_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
103
100
|
s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
|
104
|
-
s.add_development_dependency(%q<grpc-tools>.freeze, [">= 0"])
|
105
101
|
s.add_development_dependency(%q<juwelier>.freeze, ["~> 2.4.9"])
|
106
102
|
s.add_development_dependency(%q<rdoc>.freeze, [">= 0"])
|
107
103
|
s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
|
@@ -110,12 +106,10 @@ Gem::Specification.new do |s|
|
|
110
106
|
s.add_dependency(%q<faraday>.freeze, [">= 0"])
|
111
107
|
s.add_dependency(%q<googleapis-common-protos-types>.freeze, [">= 0"])
|
112
108
|
s.add_dependency(%q<google-protobuf>.freeze, [">= 0"])
|
113
|
-
s.add_dependency(%q<grpc>.freeze, [">= 0"])
|
114
109
|
s.add_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
115
110
|
s.add_dependency(%q<uuid>.freeze, [">= 0"])
|
116
111
|
s.add_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
117
112
|
s.add_dependency(%q<bundler>.freeze, [">= 0"])
|
118
|
-
s.add_dependency(%q<grpc-tools>.freeze, [">= 0"])
|
119
113
|
s.add_dependency(%q<juwelier>.freeze, ["~> 2.4.9"])
|
120
114
|
s.add_dependency(%q<rdoc>.freeze, [">= 0"])
|
121
115
|
s.add_dependency(%q<simplecov>.freeze, [">= 0"])
|
data/test/integration_test.rb
CHANGED
@@ -91,8 +91,7 @@ class IntegrationTest
|
|
91
91
|
prefab_envs: ['unit_tests'],
|
92
92
|
prefab_datasources: Prefab::Options::DATASOURCES::ALL,
|
93
93
|
api_key: ENV['PREFAB_INTEGRATION_TEST_API_KEY'],
|
94
|
-
prefab_api_url: 'https://api.staging-prefab.cloud'
|
95
|
-
prefab_grpc_url: 'grpc.staging-prefab.cloud:443'
|
94
|
+
prefab_api_url: 'https://api.staging-prefab.cloud'
|
96
95
|
}.merge(@client_overrides))
|
97
96
|
end
|
98
97
|
end
|
data/test/test_client.rb
CHANGED
@@ -77,13 +77,6 @@ class TestClient < Minitest::Test
|
|
77
77
|
assert_equal 'all-features', @client.get('flag_with_a_value')
|
78
78
|
end
|
79
79
|
|
80
|
-
def test_ssl_certs
|
81
|
-
certs = @client.send(:ssl_certs).split('-----BEGIN CERTIFICATE-----')
|
82
|
-
|
83
|
-
# This is a smoke test to make sure multiple certs are loaded
|
84
|
-
assert certs.length > 1
|
85
|
-
end
|
86
|
-
|
87
80
|
def test_initialization_with_an_options_object
|
88
81
|
options_hash = {
|
89
82
|
namespace: 'test-namespace',
|
@@ -4,6 +4,9 @@ require 'test_helper'
|
|
4
4
|
require 'timecop'
|
5
5
|
|
6
6
|
class TestLogPathCollector < Minitest::Test
|
7
|
+
MAX_WAIT = 2
|
8
|
+
SLEEP_TIME = 0.01
|
9
|
+
|
7
10
|
def test_sync
|
8
11
|
Timecop.freeze do
|
9
12
|
client = new_client(namespace: 'this.is.a.namespace')
|
@@ -13,29 +16,32 @@ class TestLogPathCollector < Minitest::Test
|
|
13
16
|
|
14
17
|
requests = []
|
15
18
|
|
16
|
-
client.define_singleton_method(:
|
19
|
+
client.define_singleton_method(:post) do |*params|
|
17
20
|
requests.push(params)
|
18
21
|
end
|
19
22
|
|
20
23
|
client.log_path_collector.send(:sync)
|
21
24
|
|
22
25
|
# let the flush thread run
|
23
|
-
|
26
|
+
|
27
|
+
wait_time = 0
|
28
|
+
while requests.length == 0
|
29
|
+
wait_time += SLEEP_TIME
|
30
|
+
sleep SLEEP_TIME
|
31
|
+
|
32
|
+
raise "Waited #{MAX_WAIT} seconds for the flush thread to run, but it never did" if wait_time > MAX_WAIT
|
33
|
+
end
|
24
34
|
|
25
35
|
assert_equal requests, [[
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
instance_hash: client.instance_hash,
|
36
|
-
namespace: 'this.is.a.namespace'
|
37
|
-
)
|
38
|
-
}
|
36
|
+
'/api/v1/known-loggers',
|
37
|
+
Prefab::Loggers.new(
|
38
|
+
loggers: [Prefab::Logger.new(logger_name: 'test.test_log_path_collector.test_sync',
|
39
|
+
infos: 2, errors: 3)],
|
40
|
+
start_at: (Time.now.utc.to_f * 1000).to_i,
|
41
|
+
end_at: (Time.now.utc.to_f * 1000).to_i,
|
42
|
+
instance_hash: client.instance_hash,
|
43
|
+
namespace: 'this.is.a.namespace'
|
44
|
+
)
|
39
45
|
]]
|
40
46
|
end
|
41
47
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prefab-cloud-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.23.
|
4
|
+
version: 0.23.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Dwyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -72,20 +72,6 @@ dependencies:
|
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '0'
|
75
|
-
- !ruby/object:Gem::Dependency
|
76
|
-
name: grpc
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - ">="
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: '0'
|
82
|
-
type: :runtime
|
83
|
-
prerelease: false
|
84
|
-
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - ">="
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: '0'
|
89
75
|
- !ruby/object:Gem::Dependency
|
90
76
|
name: ld-eventsource
|
91
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,20 +128,6 @@ dependencies:
|
|
142
128
|
- - ">="
|
143
129
|
- !ruby/object:Gem::Version
|
144
130
|
version: '0'
|
145
|
-
- !ruby/object:Gem::Dependency
|
146
|
-
name: grpc-tools
|
147
|
-
requirement: !ruby/object:Gem::Requirement
|
148
|
-
requirements:
|
149
|
-
- - ">="
|
150
|
-
- !ruby/object:Gem::Version
|
151
|
-
version: '0'
|
152
|
-
type: :development
|
153
|
-
prerelease: false
|
154
|
-
version_requirements: !ruby/object:Gem::Requirement
|
155
|
-
requirements:
|
156
|
-
- - ">="
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
version: '0'
|
159
131
|
- !ruby/object:Gem::Dependency
|
160
132
|
name: juwelier
|
161
133
|
requirement: !ruby/object:Gem::Requirement
|
@@ -198,7 +170,7 @@ dependencies:
|
|
198
170
|
- - ">="
|
199
171
|
- !ruby/object:Gem::Version
|
200
172
|
version: '0'
|
201
|
-
description:
|
173
|
+
description: Feature Flags, Live Config, and Dynamic Log Levels as a service
|
202
174
|
email: jdwyer@prefab.cloud
|
203
175
|
executables: []
|
204
176
|
extensions: []
|
@@ -220,8 +192,6 @@ files:
|
|
220
192
|
- VERSION
|
221
193
|
- compile_protos.sh
|
222
194
|
- lib/prefab-cloud-ruby.rb
|
223
|
-
- lib/prefab/auth_interceptor.rb
|
224
|
-
- lib/prefab/cancellable_interceptor.rb
|
225
195
|
- lib/prefab/client.rb
|
226
196
|
- lib/prefab/config_client.rb
|
227
197
|
- lib/prefab/config_loader.rb
|
@@ -234,6 +204,7 @@ files:
|
|
234
204
|
- lib/prefab/errors/missing_default_error.rb
|
235
205
|
- lib/prefab/exponential_backoff.rb
|
236
206
|
- lib/prefab/feature_flag_client.rb
|
207
|
+
- lib/prefab/http_connection.rb
|
237
208
|
- lib/prefab/internal_logger.rb
|
238
209
|
- lib/prefab/local_config_parser.rb
|
239
210
|
- lib/prefab/log_path_collector.rb
|
@@ -242,7 +213,6 @@ files:
|
|
242
213
|
- lib/prefab/noop_cache.rb
|
243
214
|
- lib/prefab/noop_stats.rb
|
244
215
|
- lib/prefab/options.rb
|
245
|
-
- lib/prefab/ratelimit_client.rb
|
246
216
|
- lib/prefab/sse_logger.rb
|
247
217
|
- lib/prefab/weighted_value_resolver.rb
|
248
218
|
- lib/prefab/yaml_config_parser.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
class AuthInterceptor < GRPC::ClientInterceptor
|
5
|
-
VERSION = File.exist?('VERSION') ? File.read('VERSION').chomp : ''
|
6
|
-
CLIENT = "prefab-cloud-ruby.#{VERSION}".freeze
|
7
|
-
|
8
|
-
def initialize(api_key)
|
9
|
-
@api_key = api_key
|
10
|
-
end
|
11
|
-
|
12
|
-
def request_response(request:, call:, method:, metadata:, &block)
|
13
|
-
shared(metadata, &block)
|
14
|
-
end
|
15
|
-
|
16
|
-
def client_streamer(requests:, call:, method:, metadata:, &block)
|
17
|
-
shared(metadata, &block)
|
18
|
-
end
|
19
|
-
|
20
|
-
def server_streamer(request:, call:, method:, metadata:, &block)
|
21
|
-
shared(metadata, &block)
|
22
|
-
end
|
23
|
-
|
24
|
-
def bidi_streamer(requests:, call:, method:, metadata:, &block)
|
25
|
-
shared(metadata, &block)
|
26
|
-
end
|
27
|
-
|
28
|
-
def shared(metadata)
|
29
|
-
metadata['auth'] = @api_key
|
30
|
-
metadata['client'] = CLIENT
|
31
|
-
yield
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
class CancellableInterceptor < GRPC::ClientInterceptor
|
5
|
-
WAIT_SEC = 3
|
6
|
-
|
7
|
-
def initialize(base_client)
|
8
|
-
@base_client = base_client
|
9
|
-
end
|
10
|
-
|
11
|
-
def cancel
|
12
|
-
@call.instance_variable_get('@wrapped').instance_variable_get('@call').cancel
|
13
|
-
i = 0
|
14
|
-
while i < WAIT_SEC
|
15
|
-
if @call.instance_variable_get('@wrapped').cancelled?
|
16
|
-
@base_client.log_internal ::Logger::DEBUG, 'Cancelled streaming.'
|
17
|
-
return
|
18
|
-
else
|
19
|
-
@base_client.log_internal ::Logger::DEBUG, 'Unable to cancel streaming. Trying again'
|
20
|
-
@call.instance_variable_get('@wrapped').instance_variable_get('@call').cancel
|
21
|
-
i += 1
|
22
|
-
sleep(1)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
@base_client.log_internal ::Logger::INFO, 'Unable to cancel streaming.'
|
26
|
-
end
|
27
|
-
|
28
|
-
def request_response(request:, call:, method:, metadata:, &block)
|
29
|
-
shared(call, &block)
|
30
|
-
end
|
31
|
-
|
32
|
-
def client_streamer(requests:, call:, method:, metadata:, &block)
|
33
|
-
shared(call, &block)
|
34
|
-
end
|
35
|
-
|
36
|
-
def server_streamer(request:, call:, method:, metadata:, &block)
|
37
|
-
shared(call, &block)
|
38
|
-
end
|
39
|
-
|
40
|
-
def bidi_streamer(requests:, call:, method:, metadata:, &block)
|
41
|
-
shared(call, &block)
|
42
|
-
end
|
43
|
-
|
44
|
-
def shared(call)
|
45
|
-
@call = call
|
46
|
-
yield
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,78 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Prefab
|
4
|
-
class RateLimitClient
|
5
|
-
def initialize(base_client, timeout)
|
6
|
-
@timeout = timeout
|
7
|
-
@base_client = base_client
|
8
|
-
end
|
9
|
-
|
10
|
-
def pass?(group)
|
11
|
-
result = acquire([group], 1)
|
12
|
-
result.passed
|
13
|
-
end
|
14
|
-
|
15
|
-
def acquire(groups, acquire_amount, allow_partial_response: false, on_error: :log_and_pass)
|
16
|
-
expiry_cache_key = "prefab.ratelimit.expiry:#{groups.join('.')}"
|
17
|
-
expiry = @base_client.shared_cache.read(expiry_cache_key)
|
18
|
-
if !expiry.nil? && Integer(expiry) > Time.now.utc.to_f * 1000
|
19
|
-
@base_client.stats.increment('prefab.ratelimit.limitcheck.expirycache.hit', tags: [])
|
20
|
-
return Prefab::LimitResponse.new(passed: false, amount: 0)
|
21
|
-
end
|
22
|
-
|
23
|
-
req = Prefab::LimitRequest.new(
|
24
|
-
account_id: @base_client.account_id,
|
25
|
-
acquire_amount: acquire_amount,
|
26
|
-
groups: groups,
|
27
|
-
allow_partial_response: allow_partial_response
|
28
|
-
)
|
29
|
-
|
30
|
-
result = @base_client.request Prefab::RateLimitService, :limit_check, req_options: { timeout: @timeout },
|
31
|
-
params: req
|
32
|
-
|
33
|
-
reset = result.limit_reset_at
|
34
|
-
@base_client.shared_cache.write(expiry_cache_key, reset) unless reset < 1 # protobuf default int to 0
|
35
|
-
|
36
|
-
@base_client.stats.increment('prefab.ratelimit.limitcheck',
|
37
|
-
tags: ["policy_group:#{result.policy_group}", "pass:#{result.passed}"])
|
38
|
-
|
39
|
-
result
|
40
|
-
rescue StandardError => e
|
41
|
-
handle_error(e, on_error, groups)
|
42
|
-
end
|
43
|
-
|
44
|
-
def upsert(key, policy_name, limit, burst: nil, safety_level: nil)
|
45
|
-
burst = limit if burst.nil?
|
46
|
-
limit_definition = Prefab::LimitDefinition.new(
|
47
|
-
account_id: @base_client.account_id,
|
48
|
-
policy_name: Object.const_get("Prefab::LimitResponse::LimitPolicyNames::#{policy_name}"),
|
49
|
-
limit: limit,
|
50
|
-
burst: burst
|
51
|
-
)
|
52
|
-
limit_definition.safety_level = safety_level unless safety_level.nil?
|
53
|
-
config_value = Prefab::ConfigValue.new(limit_definition: limit_definition)
|
54
|
-
config_delta = Prefab::ConfigClient.value_to_delta(key, config_value)
|
55
|
-
upsert_req = Prefab::UpsertRequest.new(config_delta: config_delta)
|
56
|
-
|
57
|
-
@base_client.request Prefab::ConfigService, :upsert, req_options: { timeout: @timeout }, params: upsert_req
|
58
|
-
end
|
59
|
-
|
60
|
-
private
|
61
|
-
|
62
|
-
def handle_error(e, on_error, groups)
|
63
|
-
@base_client.stats.increment('prefab.ratelimit.error', tags: ['type:limit'])
|
64
|
-
|
65
|
-
message = "ratelimit for #{groups} error: #{e.message}"
|
66
|
-
case on_error
|
67
|
-
when :log_and_pass
|
68
|
-
@base_client.log.warn(message)
|
69
|
-
Prefab::LimitResponse.new(passed: true, amount: 0)
|
70
|
-
when :log_and_hit
|
71
|
-
@base_client.log.warn(message)
|
72
|
-
Prefab::LimitResponse.new(passed: false, amount: 0)
|
73
|
-
when :throw
|
74
|
-
raise e
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|