launchdarkly-server-sdk 8.11.1-java → 8.11.3-java
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/lib/ldclient-rb/config.rb +66 -3
- data/lib/ldclient-rb/context.rb +1 -1
- data/lib/ldclient-rb/data_system.rb +243 -0
- data/lib/ldclient-rb/events.rb +35 -20
- data/lib/ldclient-rb/flags_state.rb +1 -1
- data/lib/ldclient-rb/impl/big_segments.rb +4 -4
- data/lib/ldclient-rb/impl/cache_store.rb +44 -0
- data/lib/ldclient-rb/impl/data_source/null_processor.rb +52 -0
- data/lib/ldclient-rb/impl/data_source/polling.rb +108 -0
- data/lib/ldclient-rb/impl/data_source/requestor.rb +106 -0
- data/lib/ldclient-rb/impl/data_source/status_provider.rb +78 -0
- data/lib/ldclient-rb/impl/data_source/stream.rb +198 -0
- data/lib/ldclient-rb/impl/data_source.rb +3 -3
- data/lib/ldclient-rb/impl/data_store/data_kind.rb +108 -0
- data/lib/ldclient-rb/impl/data_store/feature_store_client_wrapper.rb +187 -0
- data/lib/ldclient-rb/impl/data_store/in_memory_feature_store.rb +130 -0
- data/lib/ldclient-rb/impl/data_store/status_provider.rb +82 -0
- data/lib/ldclient-rb/impl/data_store/store.rb +371 -0
- data/lib/ldclient-rb/impl/data_store.rb +11 -97
- data/lib/ldclient-rb/impl/data_system/fdv1.rb +178 -0
- data/lib/ldclient-rb/impl/data_system/fdv2.rb +471 -0
- data/lib/ldclient-rb/impl/data_system/polling.rb +601 -0
- data/lib/ldclient-rb/impl/data_system/protocolv2.rb +264 -0
- data/lib/ldclient-rb/impl/data_system.rb +298 -0
- data/lib/ldclient-rb/impl/dependency_tracker.rb +21 -9
- data/lib/ldclient-rb/impl/evaluator.rb +3 -2
- data/lib/ldclient-rb/impl/event_sender.rb +4 -3
- data/lib/ldclient-rb/impl/expiring_cache.rb +79 -0
- data/lib/ldclient-rb/impl/integrations/file_data_source.rb +9 -9
- data/lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb +0 -1
- data/lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb +288 -0
- data/lib/ldclient-rb/impl/memoized_value.rb +34 -0
- data/lib/ldclient-rb/impl/migrations/migrator.rb +2 -1
- data/lib/ldclient-rb/impl/migrations/tracker.rb +2 -1
- data/lib/ldclient-rb/impl/model/serialization.rb +6 -6
- data/lib/ldclient-rb/impl/non_blocking_thread_pool.rb +48 -0
- data/lib/ldclient-rb/impl/repeating_task.rb +2 -2
- data/lib/ldclient-rb/impl/simple_lru_cache.rb +27 -0
- data/lib/ldclient-rb/impl/util.rb +65 -0
- data/lib/ldclient-rb/impl.rb +1 -2
- data/lib/ldclient-rb/in_memory_store.rb +1 -18
- data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +9 -9
- data/lib/ldclient-rb/integrations/test_data.rb +11 -11
- data/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb +582 -0
- data/lib/ldclient-rb/integrations/test_data_v2.rb +248 -0
- data/lib/ldclient-rb/integrations/util/store_wrapper.rb +3 -2
- data/lib/ldclient-rb/interfaces/data_system.rb +755 -0
- data/lib/ldclient-rb/interfaces/feature_store.rb +3 -0
- data/lib/ldclient-rb/ldclient.rb +55 -149
- data/lib/ldclient-rb/util.rb +11 -70
- data/lib/ldclient-rb/version.rb +1 -1
- data/lib/ldclient-rb.rb +8 -17
- metadata +52 -17
- data/lib/ldclient-rb/cache_store.rb +0 -45
- data/lib/ldclient-rb/expiring_cache.rb +0 -77
- data/lib/ldclient-rb/memoized_value.rb +0 -32
- data/lib/ldclient-rb/non_blocking_thread_pool.rb +0 -46
- data/lib/ldclient-rb/polling.rb +0 -102
- data/lib/ldclient-rb/requestor.rb +0 -102
- data/lib/ldclient-rb/simple_lru_cache.rb +0 -25
- data/lib/ldclient-rb/stream.rb +0 -196
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: launchdarkly-server-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.11.
|
|
4
|
+
version: 8.11.3
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- LaunchDarkly
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-01-20 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: aws-sdk-dynamodb
|
|
@@ -23,6 +23,20 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '1.57'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: bigdecimal
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 3.1.1
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 3.1.1
|
|
26
40
|
- !ruby/object:Gem::Dependency
|
|
27
41
|
name: bundler
|
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -283,22 +297,22 @@ dependencies:
|
|
|
283
297
|
name: openssl
|
|
284
298
|
requirement: !ruby/object:Gem::Requirement
|
|
285
299
|
requirements:
|
|
286
|
-
- - "~>"
|
|
287
|
-
- !ruby/object:Gem::Version
|
|
288
|
-
version: '3.1'
|
|
289
300
|
- - ">="
|
|
290
301
|
- !ruby/object:Gem::Version
|
|
291
302
|
version: 3.1.2
|
|
303
|
+
- - "<"
|
|
304
|
+
- !ruby/object:Gem::Version
|
|
305
|
+
version: '5.0'
|
|
292
306
|
type: :runtime
|
|
293
307
|
prerelease: false
|
|
294
308
|
version_requirements: !ruby/object:Gem::Requirement
|
|
295
309
|
requirements:
|
|
296
|
-
- - "~>"
|
|
297
|
-
- !ruby/object:Gem::Version
|
|
298
|
-
version: '3.1'
|
|
299
310
|
- - ">="
|
|
300
311
|
- !ruby/object:Gem::Version
|
|
301
312
|
version: 3.1.2
|
|
313
|
+
- - "<"
|
|
314
|
+
- !ruby/object:Gem::Version
|
|
315
|
+
version: '5.0'
|
|
302
316
|
- !ruby/object:Gem::Dependency
|
|
303
317
|
name: semantic
|
|
304
318
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -358,20 +372,35 @@ files:
|
|
|
358
372
|
- README.md
|
|
359
373
|
- lib/launchdarkly-server-sdk.rb
|
|
360
374
|
- lib/ldclient-rb.rb
|
|
361
|
-
- lib/ldclient-rb/cache_store.rb
|
|
362
375
|
- lib/ldclient-rb/config.rb
|
|
363
376
|
- lib/ldclient-rb/context.rb
|
|
377
|
+
- lib/ldclient-rb/data_system.rb
|
|
364
378
|
- lib/ldclient-rb/evaluation_detail.rb
|
|
365
379
|
- lib/ldclient-rb/events.rb
|
|
366
|
-
- lib/ldclient-rb/expiring_cache.rb
|
|
367
380
|
- lib/ldclient-rb/flags_state.rb
|
|
368
381
|
- lib/ldclient-rb/impl.rb
|
|
369
382
|
- lib/ldclient-rb/impl/big_segments.rb
|
|
370
383
|
- lib/ldclient-rb/impl/broadcaster.rb
|
|
384
|
+
- lib/ldclient-rb/impl/cache_store.rb
|
|
371
385
|
- lib/ldclient-rb/impl/context.rb
|
|
372
386
|
- lib/ldclient-rb/impl/context_filter.rb
|
|
373
387
|
- lib/ldclient-rb/impl/data_source.rb
|
|
388
|
+
- lib/ldclient-rb/impl/data_source/null_processor.rb
|
|
389
|
+
- lib/ldclient-rb/impl/data_source/polling.rb
|
|
390
|
+
- lib/ldclient-rb/impl/data_source/requestor.rb
|
|
391
|
+
- lib/ldclient-rb/impl/data_source/status_provider.rb
|
|
392
|
+
- lib/ldclient-rb/impl/data_source/stream.rb
|
|
374
393
|
- lib/ldclient-rb/impl/data_store.rb
|
|
394
|
+
- lib/ldclient-rb/impl/data_store/data_kind.rb
|
|
395
|
+
- lib/ldclient-rb/impl/data_store/feature_store_client_wrapper.rb
|
|
396
|
+
- lib/ldclient-rb/impl/data_store/in_memory_feature_store.rb
|
|
397
|
+
- lib/ldclient-rb/impl/data_store/status_provider.rb
|
|
398
|
+
- lib/ldclient-rb/impl/data_store/store.rb
|
|
399
|
+
- lib/ldclient-rb/impl/data_system.rb
|
|
400
|
+
- lib/ldclient-rb/impl/data_system/fdv1.rb
|
|
401
|
+
- lib/ldclient-rb/impl/data_system/fdv2.rb
|
|
402
|
+
- lib/ldclient-rb/impl/data_system/polling.rb
|
|
403
|
+
- lib/ldclient-rb/impl/data_system/protocolv2.rb
|
|
375
404
|
- lib/ldclient-rb/impl/dependency_tracker.rb
|
|
376
405
|
- lib/ldclient-rb/impl/diagnostic_events.rb
|
|
377
406
|
- lib/ldclient-rb/impl/evaluation_with_hook_result.rb
|
|
@@ -382,12 +411,15 @@ files:
|
|
|
382
411
|
- lib/ldclient-rb/impl/event_sender.rb
|
|
383
412
|
- lib/ldclient-rb/impl/event_summarizer.rb
|
|
384
413
|
- lib/ldclient-rb/impl/event_types.rb
|
|
414
|
+
- lib/ldclient-rb/impl/expiring_cache.rb
|
|
385
415
|
- lib/ldclient-rb/impl/flag_tracker.rb
|
|
386
416
|
- lib/ldclient-rb/impl/integrations/consul_impl.rb
|
|
387
417
|
- lib/ldclient-rb/impl/integrations/dynamodb_impl.rb
|
|
388
418
|
- lib/ldclient-rb/impl/integrations/file_data_source.rb
|
|
389
419
|
- lib/ldclient-rb/impl/integrations/redis_impl.rb
|
|
390
420
|
- lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb
|
|
421
|
+
- lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb
|
|
422
|
+
- lib/ldclient-rb/impl/memoized_value.rb
|
|
391
423
|
- lib/ldclient-rb/impl/migrations/migrator.rb
|
|
392
424
|
- lib/ldclient-rb/impl/migrations/tracker.rb
|
|
393
425
|
- lib/ldclient-rb/impl/model/clause.rb
|
|
@@ -395,8 +427,10 @@ files:
|
|
|
395
427
|
- lib/ldclient-rb/impl/model/preprocessed_data.rb
|
|
396
428
|
- lib/ldclient-rb/impl/model/segment.rb
|
|
397
429
|
- lib/ldclient-rb/impl/model/serialization.rb
|
|
430
|
+
- lib/ldclient-rb/impl/non_blocking_thread_pool.rb
|
|
398
431
|
- lib/ldclient-rb/impl/repeating_task.rb
|
|
399
432
|
- lib/ldclient-rb/impl/sampler.rb
|
|
433
|
+
- lib/ldclient-rb/impl/simple_lru_cache.rb
|
|
400
434
|
- lib/ldclient-rb/impl/store_client_wrapper.rb
|
|
401
435
|
- lib/ldclient-rb/impl/store_data_set_sorter.rb
|
|
402
436
|
- lib/ldclient-rb/impl/unbounded_pool.rb
|
|
@@ -409,31 +443,32 @@ files:
|
|
|
409
443
|
- lib/ldclient-rb/integrations/redis.rb
|
|
410
444
|
- lib/ldclient-rb/integrations/test_data.rb
|
|
411
445
|
- lib/ldclient-rb/integrations/test_data/flag_builder.rb
|
|
446
|
+
- lib/ldclient-rb/integrations/test_data_v2.rb
|
|
447
|
+
- lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb
|
|
412
448
|
- lib/ldclient-rb/integrations/util/store_wrapper.rb
|
|
413
449
|
- lib/ldclient-rb/interfaces.rb
|
|
414
450
|
- lib/ldclient-rb/interfaces/big_segment_store.rb
|
|
415
451
|
- lib/ldclient-rb/interfaces/data_source.rb
|
|
416
452
|
- lib/ldclient-rb/interfaces/data_store.rb
|
|
453
|
+
- lib/ldclient-rb/interfaces/data_system.rb
|
|
417
454
|
- lib/ldclient-rb/interfaces/feature_store.rb
|
|
418
455
|
- lib/ldclient-rb/interfaces/flag_tracker.rb
|
|
419
456
|
- lib/ldclient-rb/interfaces/hooks.rb
|
|
420
457
|
- lib/ldclient-rb/interfaces/migrations.rb
|
|
421
458
|
- lib/ldclient-rb/interfaces/plugins.rb
|
|
422
459
|
- lib/ldclient-rb/ldclient.rb
|
|
423
|
-
- lib/ldclient-rb/memoized_value.rb
|
|
424
460
|
- lib/ldclient-rb/migrations.rb
|
|
425
|
-
- lib/ldclient-rb/non_blocking_thread_pool.rb
|
|
426
|
-
- lib/ldclient-rb/polling.rb
|
|
427
461
|
- lib/ldclient-rb/reference.rb
|
|
428
|
-
- lib/ldclient-rb/requestor.rb
|
|
429
|
-
- lib/ldclient-rb/simple_lru_cache.rb
|
|
430
|
-
- lib/ldclient-rb/stream.rb
|
|
431
462
|
- lib/ldclient-rb/util.rb
|
|
432
463
|
- lib/ldclient-rb/version.rb
|
|
433
464
|
homepage: https://github.com/launchdarkly/ruby-server-sdk
|
|
434
465
|
licenses:
|
|
435
466
|
- Apache-2.0
|
|
436
|
-
metadata:
|
|
467
|
+
metadata:
|
|
468
|
+
bug_tracker_uri: https://github.com/launchdarkly/ruby-server-sdk/issues
|
|
469
|
+
changelog_uri: https://github.com/launchdarkly/ruby-server-sdk/blob/main/CHANGELOG.md
|
|
470
|
+
homepage_uri: https://github.com/launchdarkly/ruby-server-sdk
|
|
471
|
+
source_code_uri: https://github.com/launchdarkly/ruby-server-sdk
|
|
437
472
|
rdoc_options: []
|
|
438
473
|
require_paths:
|
|
439
474
|
- lib
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
require "concurrent/map"
|
|
2
|
-
|
|
3
|
-
module LaunchDarkly
|
|
4
|
-
#
|
|
5
|
-
# A thread-safe in-memory store that uses the same semantics that Faraday would expect, although we
|
|
6
|
-
# no longer use Faraday. This is used by Requestor, when we are not in a Rails environment.
|
|
7
|
-
#
|
|
8
|
-
# @private
|
|
9
|
-
#
|
|
10
|
-
class ThreadSafeMemoryStore
|
|
11
|
-
#
|
|
12
|
-
# Default constructor
|
|
13
|
-
#
|
|
14
|
-
# @return [ThreadSafeMemoryStore] a new store
|
|
15
|
-
def initialize
|
|
16
|
-
@cache = Concurrent::Map.new
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
-
# Read a value from the cache
|
|
21
|
-
# @param key [Object] the cache key
|
|
22
|
-
#
|
|
23
|
-
# @return [Object] the cache value
|
|
24
|
-
def read(key)
|
|
25
|
-
@cache[key]
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
#
|
|
29
|
-
# Store a value in the cache
|
|
30
|
-
# @param key [Object] the cache key
|
|
31
|
-
# @param value [Object] the value to associate with the key
|
|
32
|
-
#
|
|
33
|
-
# @return [Object] the value
|
|
34
|
-
def write(key, value)
|
|
35
|
-
@cache[key] = value
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
#
|
|
39
|
-
# Delete a value in the cache
|
|
40
|
-
# @param key [Object] the cache key
|
|
41
|
-
def delete(key)
|
|
42
|
-
@cache.delete(key)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
module LaunchDarkly
|
|
3
|
-
# A thread-safe cache with maximum number of entries and TTL.
|
|
4
|
-
# Adapted from https://github.com/SamSaffron/lru_redux/blob/master/lib/lru_redux/ttl/cache.rb
|
|
5
|
-
# under MIT license with the following changes:
|
|
6
|
-
# * made thread-safe
|
|
7
|
-
# * removed many unused methods
|
|
8
|
-
# * reading a key does not reset its expiration time, only writing
|
|
9
|
-
# @private
|
|
10
|
-
class ExpiringCache
|
|
11
|
-
def initialize(max_size, ttl)
|
|
12
|
-
@max_size = max_size
|
|
13
|
-
@ttl = ttl
|
|
14
|
-
@data_lru = {}
|
|
15
|
-
@data_ttl = {}
|
|
16
|
-
@lock = Mutex.new
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def [](key)
|
|
20
|
-
@lock.synchronize do
|
|
21
|
-
ttl_evict
|
|
22
|
-
@data_lru[key]
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def []=(key, val)
|
|
27
|
-
@lock.synchronize do
|
|
28
|
-
ttl_evict
|
|
29
|
-
|
|
30
|
-
@data_lru.delete(key)
|
|
31
|
-
@data_ttl.delete(key)
|
|
32
|
-
|
|
33
|
-
@data_lru[key] = val
|
|
34
|
-
@data_ttl[key] = Time.now.to_f
|
|
35
|
-
|
|
36
|
-
if @data_lru.size > @max_size
|
|
37
|
-
key, _ = @data_lru.first # hashes have a FIFO ordering in Ruby
|
|
38
|
-
|
|
39
|
-
@data_ttl.delete(key)
|
|
40
|
-
@data_lru.delete(key)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
val
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def delete(key)
|
|
48
|
-
@lock.synchronize do
|
|
49
|
-
ttl_evict
|
|
50
|
-
|
|
51
|
-
@data_lru.delete(key)
|
|
52
|
-
@data_ttl.delete(key)
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def clear
|
|
57
|
-
@lock.synchronize do
|
|
58
|
-
@data_lru.clear
|
|
59
|
-
@data_ttl.clear
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
def ttl_evict
|
|
66
|
-
ttl_horizon = Time.now.to_f - @ttl
|
|
67
|
-
key, time = @data_ttl.first
|
|
68
|
-
|
|
69
|
-
until time.nil? || time > ttl_horizon
|
|
70
|
-
@data_ttl.delete(key)
|
|
71
|
-
@data_lru.delete(key)
|
|
72
|
-
|
|
73
|
-
key, time = @data_ttl.first
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
module LaunchDarkly
|
|
3
|
-
# Simple implementation of a thread-safe memoized value whose generator function will never be
|
|
4
|
-
# run more than once, and whose value can be overridden by explicit assignment.
|
|
5
|
-
# Note that we no longer use this class and it will be removed in a future version.
|
|
6
|
-
# @private
|
|
7
|
-
class MemoizedValue
|
|
8
|
-
def initialize(&generator)
|
|
9
|
-
@generator = generator
|
|
10
|
-
@mutex = Mutex.new
|
|
11
|
-
@inited = false
|
|
12
|
-
@value = nil
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def get
|
|
16
|
-
@mutex.synchronize do
|
|
17
|
-
unless @inited
|
|
18
|
-
@value = @generator.call
|
|
19
|
-
@inited = true
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
@value
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def set(value)
|
|
26
|
-
@mutex.synchronize do
|
|
27
|
-
@value = value
|
|
28
|
-
@inited = true
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
require "concurrent"
|
|
2
|
-
require "concurrent/atomics"
|
|
3
|
-
require "concurrent/executors"
|
|
4
|
-
require "thread"
|
|
5
|
-
|
|
6
|
-
module LaunchDarkly
|
|
7
|
-
# Simple wrapper for a FixedThreadPool that rejects new jobs if all the threads are busy, rather
|
|
8
|
-
# than blocking. Also provides a way to wait for all jobs to finish without shutting down.
|
|
9
|
-
# @private
|
|
10
|
-
class NonBlockingThreadPool
|
|
11
|
-
def initialize(capacity, name = 'LD/NonBlockingThreadPool')
|
|
12
|
-
@capacity = capacity
|
|
13
|
-
@pool = Concurrent::FixedThreadPool.new(capacity, name: name)
|
|
14
|
-
@semaphore = Concurrent::Semaphore.new(capacity)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Attempts to submit a job, but only if a worker is available. Unlike the regular post method,
|
|
18
|
-
# this returns a value: true if the job was submitted, false if all workers are busy.
|
|
19
|
-
def post
|
|
20
|
-
unless @semaphore.try_acquire(1)
|
|
21
|
-
return
|
|
22
|
-
end
|
|
23
|
-
@pool.post do
|
|
24
|
-
begin
|
|
25
|
-
yield
|
|
26
|
-
ensure
|
|
27
|
-
@semaphore.release(1)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Waits until no jobs are executing, without shutting down the pool.
|
|
33
|
-
def wait_all
|
|
34
|
-
@semaphore.acquire(@capacity)
|
|
35
|
-
@semaphore.release(@capacity)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def shutdown
|
|
39
|
-
@pool.shutdown
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def wait_for_termination
|
|
43
|
-
@pool.wait_for_termination
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
data/lib/ldclient-rb/polling.rb
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
require "ldclient-rb/impl/repeating_task"
|
|
2
|
-
|
|
3
|
-
require "concurrent/atomics"
|
|
4
|
-
require "json"
|
|
5
|
-
require "thread"
|
|
6
|
-
|
|
7
|
-
module LaunchDarkly
|
|
8
|
-
# @private
|
|
9
|
-
class PollingProcessor
|
|
10
|
-
def initialize(config, requestor)
|
|
11
|
-
@config = config
|
|
12
|
-
@requestor = requestor
|
|
13
|
-
@initialized = Concurrent::AtomicBoolean.new(false)
|
|
14
|
-
@started = Concurrent::AtomicBoolean.new(false)
|
|
15
|
-
@ready = Concurrent::Event.new
|
|
16
|
-
@task = Impl::RepeatingTask.new(@config.poll_interval, 0, -> { self.poll }, @config.logger, 'LD/PollingDataSource')
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def initialized?
|
|
20
|
-
@initialized.value
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def start
|
|
24
|
-
return @ready unless @started.make_true
|
|
25
|
-
@config.logger.info { "[LDClient] Initializing polling connection" }
|
|
26
|
-
@task.start
|
|
27
|
-
@ready
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def stop
|
|
31
|
-
stop_with_error_info
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def poll
|
|
35
|
-
begin
|
|
36
|
-
all_data = @requestor.request_all_data
|
|
37
|
-
if all_data
|
|
38
|
-
update_sink_or_data_store.init(all_data)
|
|
39
|
-
if @initialized.make_true
|
|
40
|
-
@config.logger.info { "[LDClient] Polling connection initialized" }
|
|
41
|
-
@ready.set
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
@config.data_source_update_sink&.update_status(LaunchDarkly::Interfaces::DataSource::Status::VALID, nil)
|
|
45
|
-
rescue JSON::ParserError => e
|
|
46
|
-
@config.logger.error { "[LDClient] JSON parsing failed for polling response." }
|
|
47
|
-
error_info = LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(
|
|
48
|
-
LaunchDarkly::Interfaces::DataSource::ErrorInfo::INVALID_DATA,
|
|
49
|
-
0,
|
|
50
|
-
e.to_s,
|
|
51
|
-
Time.now
|
|
52
|
-
)
|
|
53
|
-
@config.data_source_update_sink&.update_status(LaunchDarkly::Interfaces::DataSource::Status::INTERRUPTED, error_info)
|
|
54
|
-
rescue UnexpectedResponseError => e
|
|
55
|
-
error_info = LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(
|
|
56
|
-
LaunchDarkly::Interfaces::DataSource::ErrorInfo::ERROR_RESPONSE, e.status, nil, Time.now)
|
|
57
|
-
message = Util.http_error_message(e.status, "polling request", "will retry")
|
|
58
|
-
@config.logger.error { "[LDClient] #{message}" }
|
|
59
|
-
|
|
60
|
-
if Util.http_error_recoverable?(e.status)
|
|
61
|
-
@config.data_source_update_sink&.update_status(
|
|
62
|
-
LaunchDarkly::Interfaces::DataSource::Status::INTERRUPTED,
|
|
63
|
-
error_info
|
|
64
|
-
)
|
|
65
|
-
else
|
|
66
|
-
@ready.set # if client was waiting on us, make it stop waiting - has no effect if already set
|
|
67
|
-
stop_with_error_info error_info
|
|
68
|
-
end
|
|
69
|
-
rescue StandardError => e
|
|
70
|
-
Util.log_exception(@config.logger, "Exception while polling", e)
|
|
71
|
-
@config.data_source_update_sink&.update_status(
|
|
72
|
-
LaunchDarkly::Interfaces::DataSource::Status::INTERRUPTED,
|
|
73
|
-
LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(LaunchDarkly::Interfaces::DataSource::ErrorInfo::UNKNOWN, 0, e.to_s, Time.now)
|
|
74
|
-
)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
#
|
|
79
|
-
# The original implementation of this class relied on the feature store
|
|
80
|
-
# directly, which we are trying to move away from. Customers who might have
|
|
81
|
-
# instantiated this directly for some reason wouldn't know they have to set
|
|
82
|
-
# the config's sink manually, so we have to fall back to the store if the
|
|
83
|
-
# sink isn't present.
|
|
84
|
-
#
|
|
85
|
-
# The next major release should be able to simplify this structure and
|
|
86
|
-
# remove the need for fall back to the data store because the update sink
|
|
87
|
-
# should always be present.
|
|
88
|
-
#
|
|
89
|
-
private def update_sink_or_data_store
|
|
90
|
-
@config.data_source_update_sink || @config.feature_store
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
#
|
|
94
|
-
# @param [LaunchDarkly::Interfaces::DataSource::ErrorInfo, nil] error_info
|
|
95
|
-
#
|
|
96
|
-
private def stop_with_error_info(error_info = nil)
|
|
97
|
-
@task.stop
|
|
98
|
-
@config.logger.info { "[LDClient] Polling connection stopped" }
|
|
99
|
-
@config.data_source_update_sink&.update_status(LaunchDarkly::Interfaces::DataSource::Status::OFF, error_info)
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
require "ldclient-rb/impl/model/serialization"
|
|
2
|
-
|
|
3
|
-
require "concurrent/atomics"
|
|
4
|
-
require "json"
|
|
5
|
-
require "uri"
|
|
6
|
-
require "http"
|
|
7
|
-
|
|
8
|
-
module LaunchDarkly
|
|
9
|
-
# @private
|
|
10
|
-
class UnexpectedResponseError < StandardError
|
|
11
|
-
def initialize(status)
|
|
12
|
-
@status = status
|
|
13
|
-
super("HTTP error #{status}")
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def status
|
|
17
|
-
@status
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# @private
|
|
22
|
-
class Requestor
|
|
23
|
-
CacheEntry = Struct.new(:etag, :body)
|
|
24
|
-
|
|
25
|
-
def initialize(sdk_key, config)
|
|
26
|
-
@sdk_key = sdk_key
|
|
27
|
-
@config = config
|
|
28
|
-
@http_client = LaunchDarkly::Util.new_http_client(config.base_uri, config)
|
|
29
|
-
.use(:auto_inflate)
|
|
30
|
-
.headers("Accept-Encoding" => "gzip")
|
|
31
|
-
@cache = @config.cache_store
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def request_all_data()
|
|
35
|
-
all_data = JSON.parse(make_request("/sdk/latest-all"), symbolize_names: true)
|
|
36
|
-
Impl::Model.make_all_store_data(all_data, @config.logger)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def stop
|
|
40
|
-
begin
|
|
41
|
-
@http_client.close
|
|
42
|
-
rescue
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
private
|
|
47
|
-
|
|
48
|
-
def make_request(path)
|
|
49
|
-
uri = URI(
|
|
50
|
-
Util.add_payload_filter_key(@config.base_uri + path, @config)
|
|
51
|
-
)
|
|
52
|
-
headers = {}
|
|
53
|
-
Impl::Util.default_http_headers(@sdk_key, @config).each { |k, v| headers[k] = v }
|
|
54
|
-
headers["Connection"] = "keep-alive"
|
|
55
|
-
cached = @cache.read(uri)
|
|
56
|
-
unless cached.nil?
|
|
57
|
-
headers["If-None-Match"] = cached.etag
|
|
58
|
-
end
|
|
59
|
-
response = @http_client.request("GET", uri, {
|
|
60
|
-
headers: headers,
|
|
61
|
-
})
|
|
62
|
-
status = response.status.code
|
|
63
|
-
# must fully read body for persistent connections
|
|
64
|
-
body = response.to_s
|
|
65
|
-
@config.logger.debug { "[LDClient] Got response from uri: #{uri}\n\tstatus code: #{status}\n\theaders: #{response.headers.to_h}\n\tbody: #{body}" }
|
|
66
|
-
if status == 304 && !cached.nil?
|
|
67
|
-
body = cached.body
|
|
68
|
-
else
|
|
69
|
-
@cache.delete(uri)
|
|
70
|
-
if status < 200 || status >= 300
|
|
71
|
-
raise UnexpectedResponseError.new(status)
|
|
72
|
-
end
|
|
73
|
-
body = fix_encoding(body, response.headers["content-type"])
|
|
74
|
-
etag = response.headers["etag"]
|
|
75
|
-
@cache.write(uri, CacheEntry.new(etag, body)) unless etag.nil?
|
|
76
|
-
end
|
|
77
|
-
body
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def fix_encoding(body, content_type)
|
|
81
|
-
return body if content_type.nil?
|
|
82
|
-
media_type, charset = parse_content_type(content_type)
|
|
83
|
-
return body if charset.nil?
|
|
84
|
-
body.force_encoding(Encoding::find(charset)).encode(Encoding::UTF_8)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def parse_content_type(value)
|
|
88
|
-
return [nil, nil] if value.nil? || value == ''
|
|
89
|
-
parts = value.split(/; */)
|
|
90
|
-
return [value, nil] if parts.count < 2
|
|
91
|
-
charset = nil
|
|
92
|
-
parts.each do |part|
|
|
93
|
-
fields = part.split('=')
|
|
94
|
-
if fields.count >= 2 && fields[0] == 'charset'
|
|
95
|
-
charset = fields[1]
|
|
96
|
-
break
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
[parts[0], charset]
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
module LaunchDarkly
|
|
3
|
-
# A non-thread-safe implementation of a LRU cache set with only add and reset methods.
|
|
4
|
-
# Based on https://github.com/SamSaffron/lru_redux/blob/master/lib/lru_redux/cache.rb
|
|
5
|
-
# @private
|
|
6
|
-
class SimpleLRUCacheSet
|
|
7
|
-
def initialize(capacity)
|
|
8
|
-
@values = {}
|
|
9
|
-
@capacity = capacity
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# Adds a value to the cache or marks it recent if it was already there. Returns true if already there.
|
|
13
|
-
def add(value)
|
|
14
|
-
found = true
|
|
15
|
-
@values.delete(value) { found = false }
|
|
16
|
-
@values[value] = true
|
|
17
|
-
@values.shift if @values.length > @capacity
|
|
18
|
-
found
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def clear
|
|
22
|
-
@values = {}
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|