launchdarkly-server-sdk 8.15.1 → 8.16.0
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/ldclient.rb +73 -4
- 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: b7bea0f24a78b42aa3494b0c36a0523a91671e7db9c3bb264011bc6791c020f7
|
|
4
|
+
data.tar.gz: fefb72d9bbf9febfb214268935bb289fe3175447bb56529d67a5211ee0b689d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2c17d728ec723fb03031bea1b6a96f32ce030202ae29ab1dc094cdfad8602489bd69370d95fefd8b4a17fd29b07fac868e04146b3cabb0254b23640ea2256952
|
|
7
|
+
data.tar.gz: 9fbed6b65e5ec58597e2b09823c9f6ea25ce487a51061910480a123ed8e47eb188adc24e87cf675aed83ae99bfbf2f1d9dfc83ce4c4bb88e4e930bcf23a6a184
|
data/lib/ldclient-rb/ldclient.rb
CHANGED
|
@@ -33,10 +33,6 @@ module LaunchDarkly
|
|
|
33
33
|
|
|
34
34
|
def_delegators :@config, :logger
|
|
35
35
|
|
|
36
|
-
# @!method flush
|
|
37
|
-
# Delegates to {LaunchDarkly::EventProcessorMethods#flush}.
|
|
38
|
-
def_delegator :@event_processor, :flush
|
|
39
|
-
|
|
40
36
|
# @!method data_store_status_provider
|
|
41
37
|
# Delegates to the data system {LaunchDarkly::Impl::DataSystem#data_store_status_provider}.
|
|
42
38
|
# @return [LaunchDarkly::Interfaces::DataStore::StatusProvider]
|
|
@@ -79,6 +75,12 @@ module LaunchDarkly
|
|
|
79
75
|
config.instance_id = SecureRandom.uuid
|
|
80
76
|
@config = config
|
|
81
77
|
|
|
78
|
+
# The pid of the process that owns this client's background threads. A child process that
|
|
79
|
+
# inherits this client after a fork has a different pid. See #check_forked.
|
|
80
|
+
@owner_pid = Process.pid
|
|
81
|
+
# The pid of the process in which the fork warning was last logged, or nil.
|
|
82
|
+
@fork_warned_pid = Concurrent::AtomicReference.new(nil)
|
|
83
|
+
|
|
82
84
|
start_up(wait_for_sec)
|
|
83
85
|
end
|
|
84
86
|
|
|
@@ -97,6 +99,10 @@ module LaunchDarkly
|
|
|
97
99
|
# reason, it is recommended that any listener or hook integrations be added postfork unless you are certain it can
|
|
98
100
|
# survive the forking process.
|
|
99
101
|
#
|
|
102
|
+
# If the SDK is used in a forked child process before this method is called, it logs a warning once per process.
|
|
103
|
+
# The warning says that flag updates and analytics events will not work until `postfork` is called. Calling this
|
|
104
|
+
# method clears that condition for the current process.
|
|
105
|
+
#
|
|
100
106
|
# @param wait_for_sec [Float] maximum time (in seconds) to wait for initialization
|
|
101
107
|
#
|
|
102
108
|
def postfork(wait_for_sec = 5)
|
|
@@ -105,9 +111,51 @@ module LaunchDarkly
|
|
|
105
111
|
@big_segment_store_manager = nil
|
|
106
112
|
@flag_tracker = nil
|
|
107
113
|
|
|
114
|
+
@owner_pid = Process.pid
|
|
115
|
+
@fork_warned_pid.set(nil)
|
|
116
|
+
|
|
108
117
|
start_up(wait_for_sec)
|
|
109
118
|
end
|
|
110
119
|
|
|
120
|
+
FORK_WARNING_MESSAGE = "[LDClient] This process was forked after the LDClient was created. Background threads do not " +
|
|
121
|
+
"survive a fork, so flag updates and analytics events will not work in this process. Call LDClient#postfork after forking."
|
|
122
|
+
private_constant :FORK_WARNING_MESSAGE
|
|
123
|
+
|
|
124
|
+
#
|
|
125
|
+
# Log a warning once per process if this client is used in a process that was forked after the client was created.
|
|
126
|
+
#
|
|
127
|
+
# Ruby threads do not survive a fork. A child process that inherits a client has no stream thread, no event
|
|
128
|
+
# dispatcher thread, and no timer tasks, so flag updates and analytics events stop working. The SDK does not
|
|
129
|
+
# repair this by itself; the application must call {#postfork}.
|
|
130
|
+
#
|
|
131
|
+
# The check compares the current pid with the pid recorded in the constructor or in {#postfork}. It is a single
|
|
132
|
+
# `getpid` call, which is cheap compared to a flag evaluation. The "already warned" state is stored as the pid in
|
|
133
|
+
# which the warning was logged, not as a boolean. A boolean would be copied into every child on fork, so a
|
|
134
|
+
# grandchild process would inherit "already warned" from its parent and never get its own warning.
|
|
135
|
+
#
|
|
136
|
+
private def check_forked
|
|
137
|
+
pid = Process.pid
|
|
138
|
+
return if pid == @owner_pid
|
|
139
|
+
return unless fork_breaks_client?
|
|
140
|
+
|
|
141
|
+
if @fork_warned_pid.get_and_set(pid) != pid
|
|
142
|
+
@config.logger.warn { FORK_WARNING_MESSAGE }
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
#
|
|
147
|
+
# Return true if this configuration needs background threads. Offline mode has none. LDD mode with events
|
|
148
|
+
# disabled reads flags from the persistent store and sends nothing, so a fork does not break it.
|
|
149
|
+
#
|
|
150
|
+
# @return [Boolean]
|
|
151
|
+
#
|
|
152
|
+
private def fork_breaks_client?
|
|
153
|
+
return false if @config.offline?
|
|
154
|
+
return false if @config.use_ldd? && !@config.send_events
|
|
155
|
+
|
|
156
|
+
true
|
|
157
|
+
end
|
|
158
|
+
|
|
111
159
|
private def start_up(wait_for_sec)
|
|
112
160
|
environment_metadata = get_environment_metadata
|
|
113
161
|
plugin_hooks = get_plugin_hooks(environment_metadata)
|
|
@@ -281,6 +329,7 @@ module LaunchDarkly
|
|
|
281
329
|
# @return the variation for the provided context, or the default value if there's an error
|
|
282
330
|
#
|
|
283
331
|
def variation(key, context, default)
|
|
332
|
+
check_forked
|
|
284
333
|
context = Impl::Context::make_context(context)
|
|
285
334
|
result = evaluate_with_hooks(key, context, default, :variation) do
|
|
286
335
|
detail, _, _ = variation_with_flag(key, context, default)
|
|
@@ -314,6 +363,7 @@ module LaunchDarkly
|
|
|
314
363
|
# @return [EvaluationDetail] an object describing the result
|
|
315
364
|
#
|
|
316
365
|
def variation_detail(key, context, default)
|
|
366
|
+
check_forked
|
|
317
367
|
context = Impl::Context::make_context(context)
|
|
318
368
|
result = evaluate_with_hooks(key, context, default, :variation_detail) do
|
|
319
369
|
detail, _, _ = evaluate_internal(key, context, default, true)
|
|
@@ -439,6 +489,7 @@ module LaunchDarkly
|
|
|
439
489
|
# @return [Array<Symbol, Interfaces::Migrations::OpTracker>]
|
|
440
490
|
#
|
|
441
491
|
def migration_variation(key, context, default_stage)
|
|
492
|
+
check_forked
|
|
442
493
|
unless Migrations::VALID_STAGES.include? default_stage
|
|
443
494
|
@config.logger.error { "[LDClient] default_stage #{default_stage} is not a valid stage; continuing with 'off' as default" }
|
|
444
495
|
default_stage = Migrations::STAGE_OFF
|
|
@@ -480,6 +531,7 @@ module LaunchDarkly
|
|
|
480
531
|
# @return [void]
|
|
481
532
|
#
|
|
482
533
|
def identify(context)
|
|
534
|
+
check_forked
|
|
483
535
|
context = LaunchDarkly::Impl::Context.make_context(context)
|
|
484
536
|
unless context.valid?
|
|
485
537
|
@config.logger.warn("Identify called with invalid context: #{context.error}")
|
|
@@ -516,6 +568,7 @@ module LaunchDarkly
|
|
|
516
568
|
# @return [void]
|
|
517
569
|
#
|
|
518
570
|
def track(event_name, context, data = nil, metric_value = nil)
|
|
571
|
+
check_forked
|
|
519
572
|
context = LaunchDarkly::Impl::Context.make_context(context)
|
|
520
573
|
unless context.valid?
|
|
521
574
|
@config.logger.warn("Track called with invalid context: #{context.error}")
|
|
@@ -536,6 +589,7 @@ module LaunchDarkly
|
|
|
536
589
|
# @param tracker [LaunchDarkly::Interfaces::Migrations::OpTracker]
|
|
537
590
|
#
|
|
538
591
|
def track_migration_op(tracker)
|
|
592
|
+
check_forked
|
|
539
593
|
unless tracker.is_a? LaunchDarkly::Interfaces::Migrations::OpTracker
|
|
540
594
|
@config.logger.error { "invalid op tracker received in track_migration_op" }
|
|
541
595
|
return
|
|
@@ -571,6 +625,8 @@ module LaunchDarkly
|
|
|
571
625
|
def all_flags_state(context, options={})
|
|
572
626
|
return FeatureFlagsState.new(false) if @config.offline?
|
|
573
627
|
|
|
628
|
+
check_forked
|
|
629
|
+
|
|
574
630
|
unless initialized?
|
|
575
631
|
if @data_system.store.initialized?
|
|
576
632
|
@config.logger.warn { "Called all_flags_state before client initialization; using last known values from data store" }
|
|
@@ -628,11 +684,24 @@ module LaunchDarkly
|
|
|
628
684
|
state
|
|
629
685
|
end
|
|
630
686
|
|
|
687
|
+
#
|
|
688
|
+
# Tells the client that all pending analytics events should be delivered as soon as possible.
|
|
689
|
+
#
|
|
690
|
+
# Delegates to {LaunchDarkly::EventProcessorMethods#flush}.
|
|
691
|
+
#
|
|
692
|
+
# @return [void]
|
|
693
|
+
#
|
|
694
|
+
def flush
|
|
695
|
+
check_forked
|
|
696
|
+
@event_processor.flush
|
|
697
|
+
end
|
|
698
|
+
|
|
631
699
|
#
|
|
632
700
|
# Releases all network connections and other resources held by the client, making it no longer usable.
|
|
633
701
|
#
|
|
634
702
|
# @return [void]
|
|
635
703
|
def close
|
|
704
|
+
check_forked
|
|
636
705
|
@config.logger.info { "[LDClient] Closing LaunchDarkly client..." }
|
|
637
706
|
@data_system.stop
|
|
638
707
|
@event_processor.stop
|
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.
|
|
4
|
+
version: 8.16.0
|
|
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-09-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: aws-sdk-dynamodb
|