Skip to content

Commit 06f11f0

Browse files
authored
fix: Modify data kind constants to avoid Process.warmup rehash (#301)
The data stores in the SDK have to deal with multiple types of data -- features (or flags) and segments. These types have long been simple hashes in our SDK, with one defining an optional lambda property. With Ruby 3.3 and the introduction of `Process.warmup`, we have seen an issue where, after warmup, the in memory store needs a `rehash` method call before these kind constants can be used reliably to access the store. To combat this, I am moving these kinds into a class. This class as explicit hash key behaviors, so theoretically shouldn't have this problem Local testing has shown this to be the case. This class is also given a dictionary interface to maintain compliance with the existing implementation. While people should not be relying on these constants explicitly, they do flow through the system in ways that might make their signatures somewhat public.
1 parent 354ef13 commit 06f11f0

File tree

2 files changed

+52
-9
lines changed

2 files changed

+52
-9
lines changed

lib/ldclient-rb/impl/data_store.rb

+50
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,56 @@
44
module LaunchDarkly
55
module Impl
66
module DataStore
7+
8+
class DataKind
9+
FEATURES = "features".freeze
10+
SEGMENTS = "segments".freeze
11+
12+
FEATURE_PREREQ_FN = lambda { |flag| (flag[:prerequisites] || []).map { |p| p[:key] } }.freeze
13+
14+
attr_reader :namespace
15+
attr_reader :priority
16+
17+
#
18+
# @param namespace [String]
19+
# @param priority [Integer]
20+
#
21+
def initialize(namespace:, priority:)
22+
@namespace = namespace
23+
@priority = priority
24+
end
25+
26+
#
27+
# Maintain the same behavior when these data kinds were standard ruby hashes.
28+
#
29+
# @param key [Symbol]
30+
# @return [Object]
31+
#
32+
def [](key)
33+
return priority if key == :priority
34+
return namespace if key == :namespace
35+
return get_dependency_keys_fn() if key == :get_dependency_keys
36+
nil
37+
end
38+
39+
#
40+
# Retrieve the dependency keys for a particular data kind. Right now, this is only defined for flags.
41+
#
42+
def get_dependency_keys_fn()
43+
return nil unless @namespace == FEATURES
44+
45+
FEATURE_PREREQ_FN
46+
end
47+
48+
def eql?(other)
49+
namespace == other.namespace && priority == other.priority
50+
end
51+
52+
def hash
53+
[namespace, priority].hash
54+
end
55+
end
56+
757
class StatusProvider
858
include LaunchDarkly::Interfaces::DataStore::StatusProvider
959

lib/ldclient-rb/in_memory_store.rb

+2-9
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,10 @@ module LaunchDarkly
1111
# to ensure data consistency during non-atomic updates.
1212

1313
# @private
14-
FEATURES = {
15-
namespace: "features",
16-
priority: 1, # that is, features should be stored after segments
17-
get_dependency_keys: lambda { |flag| (flag[:prerequisites] || []).map { |p| p[:key] } },
18-
}.freeze
14+
FEATURES = Impl::DataStore::DataKind.new(namespace: "features", priority: 1).freeze
1915

2016
# @private
21-
SEGMENTS = {
22-
namespace: "segments",
23-
priority: 0,
24-
}.freeze
17+
SEGMENTS = Impl::DataStore::DataKind.new(namespace: "segments", priority: 0).freeze
2518

2619
# @private
2720
ALL_KINDS = [FEATURES, SEGMENTS].freeze

0 commit comments

Comments
 (0)