launchdarkly-server-sdk 8.18.0 → 8.18.1
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/impl/big_segments.rb +28 -7
- data/lib/ldclient-rb/impl/data_source/polling.rb +7 -4
- data/lib/ldclient-rb/impl/data_source/stream.rb +1 -0
- data/lib/ldclient-rb/impl/data_system/fdv2.rb +8 -5
- data/lib/ldclient-rb/impl/data_system/streaming.rb +1 -0
- data/lib/ldclient-rb/impl/integrations/consul_impl.rb +8 -6
- data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +4 -1
- data/lib/ldclient-rb/impl/store_client_wrapper.rb +13 -7
- data/lib/ldclient-rb/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 911f611485b4aee247de0914c23169d847c130f4053669c363d55080d4c71ace
|
|
4
|
+
data.tar.gz: fed937b0ec2a0b265dc01049cff2c8453970f6480dbd21711dffece525d55ef1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b77e71d79a713370c10733fee8b3d16808cc06635fdb6f63861e020687fe096f1f2befaec578d68d63878e1126c39098aa5b88abee3d92dab45ac1eb91cae0dd
|
|
7
|
+
data.tar.gz: f0f69217e0707543248265cc87f7186a97d0eadf1978420cf71b0b86df66f7960db765ba6414af5c5f9a62187e5de177bb5da94fe0a7f36b3c09dcd016d416a0
|
|
@@ -21,6 +21,7 @@ module LaunchDarkly
|
|
|
21
21
|
@status_provider = BigSegmentStoreStatusProviderImpl.new(-> { get_status })
|
|
22
22
|
@logger = logger
|
|
23
23
|
@last_status = nil
|
|
24
|
+
@poll_lock = Mutex.new
|
|
24
25
|
|
|
25
26
|
unless @store.nil?
|
|
26
27
|
@cache = ExpiringCache.new(big_segments_config.context_cache_size, big_segments_config.context_cache_time)
|
|
@@ -49,18 +50,41 @@ module LaunchDarkly
|
|
|
49
50
|
return BigSegmentMembershipResult.new(nil, BigSegmentsStatus::STORE_ERROR)
|
|
50
51
|
end
|
|
51
52
|
end
|
|
52
|
-
|
|
53
|
-
unless
|
|
53
|
+
status = get_status
|
|
54
|
+
unless status.available
|
|
54
55
|
return BigSegmentMembershipResult.new(membership, BigSegmentsStatus::STORE_ERROR)
|
|
55
56
|
end
|
|
56
|
-
BigSegmentMembershipResult.new(membership,
|
|
57
|
+
BigSegmentMembershipResult.new(membership, status.stale ? BigSegmentsStatus::STALE : BigSegmentsStatus::HEALTHY)
|
|
57
58
|
end
|
|
58
59
|
|
|
59
60
|
def get_status
|
|
60
|
-
@last_status
|
|
61
|
+
status = @last_status
|
|
62
|
+
return status if status
|
|
63
|
+
|
|
64
|
+
new_status = @poll_lock.synchronize do
|
|
65
|
+
# Another caller may have finished a poll while we waited for the lock.
|
|
66
|
+
status = @last_status
|
|
67
|
+
return status if status
|
|
68
|
+
|
|
69
|
+
query_store_status
|
|
70
|
+
end
|
|
71
|
+
@status_provider.update_status(new_status)
|
|
72
|
+
|
|
73
|
+
new_status
|
|
61
74
|
end
|
|
62
75
|
|
|
63
76
|
def poll_store_and_update_status
|
|
77
|
+
new_status = @poll_lock.synchronize { query_store_status }
|
|
78
|
+
@status_provider.update_status(new_status)
|
|
79
|
+
|
|
80
|
+
new_status
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
#
|
|
84
|
+
# Queries the store and caches the result. Callers hold @poll_lock, so this must not notify
|
|
85
|
+
# observers - a listener that calls back into the manager would deadlock on the mutex.
|
|
86
|
+
#
|
|
87
|
+
private def query_store_status
|
|
64
88
|
new_status = Interfaces::BigSegmentStoreStatus.new(false, false) # default to "unavailable" if we don't get a new status below
|
|
65
89
|
unless @store.nil?
|
|
66
90
|
begin
|
|
@@ -71,9 +95,6 @@ module LaunchDarkly
|
|
|
71
95
|
end
|
|
72
96
|
end
|
|
73
97
|
@last_status = new_status
|
|
74
|
-
@status_provider.update_status(new_status)
|
|
75
|
-
|
|
76
|
-
new_status
|
|
77
98
|
end
|
|
78
99
|
|
|
79
100
|
def stale?(timestamp)
|
|
@@ -38,14 +38,17 @@ module LaunchDarkly
|
|
|
38
38
|
begin
|
|
39
39
|
all_data, headers = request_all_data
|
|
40
40
|
DataSource.record_environment_id(@config.data_source_update_sink, headers)
|
|
41
|
+
newly_initialized = false
|
|
41
42
|
if all_data
|
|
42
43
|
update_sink_or_data_store.init(all_data)
|
|
43
|
-
|
|
44
|
-
@config.logger.info { "[LDClient] Polling connection initialized" }
|
|
45
|
-
@ready.set
|
|
46
|
-
end
|
|
44
|
+
newly_initialized = @initialized.make_true
|
|
47
45
|
end
|
|
48
46
|
@config.data_source_update_sink&.update_status(LaunchDarkly::Interfaces::DataSource::Status::VALID, nil)
|
|
47
|
+
|
|
48
|
+
if newly_initialized
|
|
49
|
+
@config.logger.info { "[LDClient] Polling connection initialized" }
|
|
50
|
+
@ready.set
|
|
51
|
+
end
|
|
49
52
|
rescue JSON::ParserError => e
|
|
50
53
|
@config.logger.error { "[LDClient] JSON parsing failed for polling response." }
|
|
51
54
|
error_info = LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(
|
|
@@ -292,6 +292,10 @@ module LaunchDarkly
|
|
|
292
292
|
|
|
293
293
|
# Set ready event if and only if a selector is defined for the changeset.
|
|
294
294
|
if basis.change_set.selector && basis.change_set.selector.defined?
|
|
295
|
+
@data_source_status_provider.update_status(
|
|
296
|
+
LaunchDarkly::Interfaces::DataSource::Status::VALID,
|
|
297
|
+
nil
|
|
298
|
+
)
|
|
295
299
|
@ready_event.set
|
|
296
300
|
return fallback
|
|
297
301
|
end
|
|
@@ -473,15 +477,14 @@ module LaunchDarkly
|
|
|
473
477
|
# Handle the update
|
|
474
478
|
@store.apply(update.change_set, true) if update.change_set
|
|
475
479
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
@ready_event.set
|
|
479
|
-
record_environment_id(update.environment_id)
|
|
480
|
-
end
|
|
480
|
+
valid = update.state == LaunchDarkly::Interfaces::DataSource::Status::VALID
|
|
481
|
+
record_environment_id(update.environment_id) if valid
|
|
481
482
|
|
|
482
483
|
# Update status
|
|
483
484
|
@data_source_status_provider.update_status(update.state, update.error)
|
|
484
485
|
|
|
486
|
+
@ready_event.set if valid
|
|
487
|
+
|
|
485
488
|
return SyncResult::FDV1 if update.fallback_to_fdv1
|
|
486
489
|
|
|
487
490
|
return SyncResult::REMOVE if update.state == LaunchDarkly::Interfaces::DataSource::Status::OFF
|
|
@@ -68,13 +68,15 @@ module LaunchDarkly
|
|
|
68
68
|
|
|
69
69
|
def get_all_internal(kind)
|
|
70
70
|
items_out = {}
|
|
71
|
-
|
|
72
|
-
(
|
|
71
|
+
prefix = kind_key(kind)
|
|
72
|
+
Diplomat::Kv.get_all(prefix, {}, :return).each do |result|
|
|
73
73
|
value = result[:value]
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
next if value.nil?
|
|
75
|
+
db_key = result[:key].to_s
|
|
76
|
+
next unless db_key.start_with?(prefix)
|
|
77
|
+
# Use the key that the item is stored under, not the key inside the item. A deleted
|
|
78
|
+
# item (a "tombstone") is not guaranteed to carry a key of its own.
|
|
79
|
+
items_out[db_key[prefix.length..].to_sym] = Model.deserialize(kind, value)
|
|
78
80
|
end
|
|
79
81
|
items_out
|
|
80
82
|
end
|
|
@@ -113,7 +113,10 @@ module LaunchDarkly
|
|
|
113
113
|
resp = @client.query(req)
|
|
114
114
|
resp.items.each do |item|
|
|
115
115
|
item_out = unmarshal_item(kind, item)
|
|
116
|
-
|
|
116
|
+
next if item_out.nil?
|
|
117
|
+
# Use the sort key that the item is stored under, not the key inside the item. A
|
|
118
|
+
# deleted item (a "tombstone") is not guaranteed to carry a key of its own.
|
|
119
|
+
items_out[item[SORT_KEY].to_sym] = item_out
|
|
117
120
|
end
|
|
118
121
|
break if resp.last_evaluated_key.nil? || resp.last_evaluated_key.length == 0
|
|
119
122
|
req.exclusive_start_key = resp.last_evaluated_key
|
|
@@ -23,6 +23,7 @@ module LaunchDarkly
|
|
|
23
23
|
|
|
24
24
|
@mutex = Mutex.new # Covers the following variables
|
|
25
25
|
@last_available = true
|
|
26
|
+
@stopped = false
|
|
26
27
|
# @type [LaunchDarkly::Impl::RepeatingTask, nil]
|
|
27
28
|
@poller = nil
|
|
28
29
|
end
|
|
@@ -53,12 +54,14 @@ module LaunchDarkly
|
|
|
53
54
|
|
|
54
55
|
def stop
|
|
55
56
|
@store.stop
|
|
56
|
-
@mutex.synchronize do
|
|
57
|
-
return if @poller.nil?
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
poller = @mutex.synchronize do
|
|
59
|
+
@stopped = true
|
|
60
|
+
task = @poller
|
|
60
61
|
@poller = nil
|
|
62
|
+
task
|
|
61
63
|
end
|
|
64
|
+
poller&.stop
|
|
62
65
|
end
|
|
63
66
|
|
|
64
67
|
def monitoring_enabled?
|
|
@@ -87,12 +90,12 @@ module LaunchDarkly
|
|
|
87
90
|
@store_update_sink.update_status(status)
|
|
88
91
|
|
|
89
92
|
if available
|
|
90
|
-
@mutex.synchronize do
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@poller.stop
|
|
93
|
+
poller = @mutex.synchronize do
|
|
94
|
+
task = @poller
|
|
94
95
|
@poller = nil
|
|
96
|
+
task
|
|
95
97
|
end
|
|
98
|
+
poller&.stop
|
|
96
99
|
|
|
97
100
|
return
|
|
98
101
|
end
|
|
@@ -102,6 +105,9 @@ module LaunchDarkly
|
|
|
102
105
|
task = Impl::RepeatingTask.new(0.5, 0, -> { self.check_availability }, @logger, 'LD/StoreWrapper#check_availability')
|
|
103
106
|
|
|
104
107
|
@mutex.synchronize do
|
|
108
|
+
# A read can fail after stop, and a poller started then would never be stopped.
|
|
109
|
+
next if @stopped
|
|
110
|
+
|
|
105
111
|
@poller = task
|
|
106
112
|
@poller.start
|
|
107
113
|
end
|
data/lib/ldclient-rb/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: launchdarkly-server-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.18.
|
|
4
|
+
version: 8.18.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LaunchDarkly
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: aws-sdk-dynamodb
|