Skip to content

Commit 14424e2

Browse files
authored
Merge pull request #65 from launchdarkly/eb/ch18860/fail-fast-init
fail fast in initialization if there's a 401
2 parents c81e795 + 3755d2b commit 14424e2

File tree

5 files changed

+41
-26
lines changed

5 files changed

+41
-26
lines changed

ldclient-rb.gemspec

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,4 @@ Gem::Specification.new do |spec|
5656
else
5757
spec.add_runtime_dependency "nio4r", "~> 1.1" # for maximum ruby version compatibility.
5858
end
59-
60-
spec.add_runtime_dependency "waitutil", "0.2"
6159
end

lib/ldclient-rb/ldclient.rb

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
require "concurrent/atomics"
12
require "digest/sha1"
23
require "logger"
34
require "benchmark"
4-
require "waitutil"
55
require "json"
66
require "openssl"
77

@@ -41,7 +41,9 @@ def initialize(sdk_key, config = Config.default, wait_for_sec = 5)
4141

4242
requestor = Requestor.new(sdk_key, config)
4343

44-
if !@config.offline?
44+
if @config.offline?
45+
@update_processor = NullUpdateProcessor.new
46+
else
4547
if @config.update_processor.nil?
4648
if @config.stream?
4749
@update_processor = StreamProcessor.new(sdk_key, config, requestor)
@@ -53,16 +55,15 @@ def initialize(sdk_key, config = Config.default, wait_for_sec = 5)
5355
else
5456
@update_processor = @config.update_processor
5557
end
56-
@update_processor.start
5758
end
5859

59-
if !@config.offline? && wait_for_sec > 0
60-
begin
61-
WaitUtil.wait_for_condition("LaunchDarkly client initialization", timeout_sec: wait_for_sec, delay_sec: 0.1) do
62-
initialized?
63-
end
64-
rescue WaitUtil::TimeoutError
60+
ready = @update_processor.start
61+
if wait_for_sec > 0
62+
ok = ready.wait(wait_for_sec)
63+
if !ok
6564
@config.logger.error { "[LDClient] Timeout encountered waiting for LaunchDarkly client initialization" }
65+
elsif !@update_processor.initialized?
66+
@config.logger.error { "[LDClient] LaunchDarkly client initialization failed" }
6667
end
6768
end
6869
end
@@ -220,9 +221,7 @@ def all_flags(user)
220221
# @return [void]
221222
def close
222223
@config.logger.info { "[LDClient] Closing LaunchDarkly client..." }
223-
if not @config.offline?
224-
@update_processor.stop
225-
end
224+
@update_processor.stop
226225
@event_processor.stop
227226
@store.stop
228227
end
@@ -255,4 +254,22 @@ def make_feature_event(flag, user, variation, value, default)
255254

256255
private :evaluate, :log_exception, :sanitize_user, :make_feature_event
257256
end
257+
258+
#
259+
# Used internally when the client is offline.
260+
#
261+
class NullUpdateProcessor
262+
def start
263+
e = Concurrent::Event.new
264+
e.set
265+
e
266+
end
267+
268+
def initialized?
269+
true
270+
end
271+
272+
def stop
273+
end
274+
end
258275
end

lib/ldclient-rb/polling.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@ def initialize(config, requestor)
99
@initialized = Concurrent::AtomicBoolean.new(false)
1010
@started = Concurrent::AtomicBoolean.new(false)
1111
@stopped = Concurrent::AtomicBoolean.new(false)
12+
@ready = Concurrent::Event.new
1213
end
1314

1415
def initialized?
1516
@initialized.value
1617
end
1718

1819
def start
19-
return unless @started.make_true
20+
return @ready unless @started.make_true
2021
@config.logger.info { "[LDClient] Initializing polling connection" }
2122
create_worker
23+
@ready
2224
end
2325

2426
def stop
@@ -39,6 +41,7 @@ def poll
3941
})
4042
if @initialized.make_true
4143
@config.logger.info { "[LDClient] Polling connection initialized" }
44+
@ready.set
4245
end
4346
end
4447
end
@@ -56,6 +59,7 @@ def create_worker
5659
end
5760
rescue InvalidSDKKeyError
5861
@config.logger.error { "[LDClient] Received 401 error, no further polling requests will be made since SDK key is invalid" };
62+
@ready.set # if client was waiting on us, make it stop waiting - has no effect if already set
5963
stop
6064
rescue StandardError => exn
6165
@config.logger.error { "[LDClient] Exception while polling: #{exn.inspect}" }

lib/ldclient-rb/stream.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ def initialize(sdk_key, config, requestor)
2424
@initialized = Concurrent::AtomicBoolean.new(false)
2525
@started = Concurrent::AtomicBoolean.new(false)
2626
@stopped = Concurrent::AtomicBoolean.new(false)
27+
@ready = Concurrent::Event.new
2728
end
2829

2930
def initialized?
3031
@initialized.value
3132
end
3233

3334
def start
34-
return unless @started.make_true
35+
return @ready unless @started.make_true
3536

3637
@config.logger.info { "[LDClient] Initializing stream connection" }
3738

@@ -51,10 +52,13 @@ def start
5152
@config.logger.error { "[LDClient] Unexpected status code #{err[:status_code]} from streaming connection" }
5253
if err[:status_code] == 401
5354
@config.logger.error { "[LDClient] Received 401 error, no further streaming connection will be made since SDK key is invalid" }
55+
@ready.set # if client was waiting on us, make it stop waiting - has no effect if already set
5456
stop
5557
end
5658
}
5759
end
60+
61+
@ready
5862
end
5963

6064
def stop
@@ -83,6 +87,7 @@ def process_message(message, method)
8387
})
8488
@initialized.make_true
8589
@config.logger.info { "[LDClient] Stream initialized" }
90+
@ready.set
8691
elsif method == PATCH
8792
message = JSON.parse(message.data, symbolize_names: true)
8893
for kind in [FEATURES, SEGMENTS]

spec/ldclient_spec.rb

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
let(:offline_client) do
88
subject.new("secret", offline_config)
99
end
10-
let(:update_processor) { NullUpdateProcessor.new }
10+
let(:update_processor) { LaunchDarkly::NullUpdateProcessor.new }
1111
let(:config) { LaunchDarkly::Config.new({send_events: false, update_processor: update_processor}) }
1212
let(:client) do
1313
subject.new("secret", config)
@@ -160,13 +160,4 @@ def event_processor
160160
expect(ep).not_to be_a(LaunchDarkly::NullEventProcessor)
161161
end
162162
end
163-
164-
class NullUpdateProcessor
165-
def start
166-
end
167-
168-
def initialized?
169-
true
170-
end
171-
end
172163
end

0 commit comments

Comments
 (0)