smplkit 2.0.2 → 2.0.3
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/smplkit/flags/client.rb +35 -7
- data/lib/smplkit/management/buffer.rb +15 -0
- data/lib/smplkit/management/client.rb +20 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30020aa708d634ffe321a30d974c3f7963eedb3f0c02008d37989bd956a8cefe
|
|
4
|
+
data.tar.gz: bee093803b8614ab3d36753f59b99ddbc10b012ccd0718f4fdf7b28e1b322baa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0397940b7bfab7871f4f8c9e7e108ba16d82f4f2b7aa444af185a8caa9d095d183e3f7ae011d0e8b45a6d363d3188dcc832cb7268b7ee2f68dbda4a44b548135'
|
|
7
|
+
data.tar.gz: 356964cbc4b413c5e836866fabb98b335d0c2d8bc4ecbb6f61949a641297bc2b4aa326c52c838e82a075288b57540fd4f56d874dffae923dde261e888a054fbc
|
data/lib/smplkit/flags/client.rb
CHANGED
|
@@ -79,6 +79,9 @@ module Smplkit
|
|
|
79
79
|
# +mgmt.flags.*+. Per-request context is set via
|
|
80
80
|
# +client.set_context([...])+.
|
|
81
81
|
class FlagsClient
|
|
82
|
+
INITIAL_START_RETRY_DELAY = 1.0
|
|
83
|
+
MAX_START_RETRY_DELAY = 60.0
|
|
84
|
+
|
|
82
85
|
def initialize(parent, manage:, metrics:, flags_base_url:, app_base_url:)
|
|
83
86
|
@parent = parent
|
|
84
87
|
@manage = manage
|
|
@@ -90,6 +93,9 @@ module Smplkit
|
|
|
90
93
|
|
|
91
94
|
@flag_store = {}
|
|
92
95
|
@connected = false
|
|
96
|
+
@ws_subscribed = false
|
|
97
|
+
@next_start_attempt_at = 0.0
|
|
98
|
+
@start_retry_delay = INITIAL_START_RETRY_DELAY
|
|
93
99
|
@cache = ResolutionCache.new
|
|
94
100
|
@handles = {}
|
|
95
101
|
@global_listeners = []
|
|
@@ -116,24 +122,44 @@ module Smplkit
|
|
|
116
122
|
|
|
117
123
|
# Eagerly initialize the flags subclient.
|
|
118
124
|
#
|
|
119
|
-
#
|
|
125
|
+
# Flushes any pending flag-declaration buffer, fetches all flag
|
|
120
126
|
# definitions, opens the shared WebSocket and subscribes to
|
|
121
127
|
# +flag_changed+ / +flag_deleted+ / +flags_changed+ events.
|
|
122
128
|
#
|
|
123
129
|
# Idempotent — safe to call multiple times. Called automatically on
|
|
124
130
|
# first +flag.get+ evaluation if not invoked manually.
|
|
131
|
+
#
|
|
132
|
+
# If the flags-service is unhealthy (e.g. a coordinated rebuild where
|
|
133
|
+
# the app pod starts before the schema is loaded), the flush or refresh
|
|
134
|
+
# will fail. Pending declarations stay queued, the client remains
|
|
135
|
+
# disconnected, and the next call retries after an exponentially
|
|
136
|
+
# backed-off delay (capped at +MAX_START_RETRY_DELAY+ seconds).
|
|
137
|
+
# Evaluations during that window fall back to handle defaults.
|
|
125
138
|
def start
|
|
126
139
|
return if @connected
|
|
140
|
+
return if Process.clock_gettime(Process::CLOCK_MONOTONIC) < @next_start_attempt_at
|
|
127
141
|
|
|
128
142
|
@environment = @parent._environment
|
|
129
|
-
|
|
130
|
-
|
|
143
|
+
|
|
144
|
+
begin
|
|
145
|
+
@manage.flags.flush
|
|
146
|
+
refresh
|
|
147
|
+
rescue StandardError => e
|
|
148
|
+
schedule_start_retry(e)
|
|
149
|
+
return
|
|
150
|
+
end
|
|
151
|
+
|
|
131
152
|
@connected = true
|
|
153
|
+
@start_retry_delay = INITIAL_START_RETRY_DELAY
|
|
154
|
+
@next_start_attempt_at = 0.0
|
|
132
155
|
|
|
133
156
|
@ws_manager = @parent._ensure_ws
|
|
157
|
+
return if @ws_subscribed
|
|
158
|
+
|
|
134
159
|
@ws_manager.on("flag_changed") { |data| handle_flag_changed(data) }
|
|
135
160
|
@ws_manager.on("flag_deleted") { |data| handle_flag_deleted(data) }
|
|
136
161
|
@ws_manager.on("flags_changed") { |data| handle_flags_changed(data) }
|
|
162
|
+
@ws_subscribed = true
|
|
137
163
|
end
|
|
138
164
|
|
|
139
165
|
def refresh
|
|
@@ -217,10 +243,12 @@ module Smplkit
|
|
|
217
243
|
handle
|
|
218
244
|
end
|
|
219
245
|
|
|
220
|
-
def
|
|
221
|
-
@
|
|
222
|
-
|
|
223
|
-
|
|
246
|
+
def schedule_start_retry(exc)
|
|
247
|
+
delay = @start_retry_delay
|
|
248
|
+
@next_start_attempt_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + delay
|
|
249
|
+
@start_retry_delay = [delay * 2, MAX_START_RETRY_DELAY].min
|
|
250
|
+
Smplkit.debug("registration",
|
|
251
|
+
"flags client start failed (will retry in #{delay}s): #{exc.class}: #{exc.message}")
|
|
224
252
|
end
|
|
225
253
|
|
|
226
254
|
def fetch_all_flags
|
|
@@ -42,6 +42,10 @@ module Smplkit
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
# Thread-safe batch buffer for flag declarations.
|
|
45
|
+
#
|
|
46
|
+
# Use +peek+ + +commit(ids)+ for the send path so a failed POST leaves
|
|
47
|
+
# declarations queued for the next attempt. +drain+ is unconditional and
|
|
48
|
+
# used only by tests/teardown.
|
|
45
49
|
class FlagRegistrationBuffer
|
|
46
50
|
def initialize
|
|
47
51
|
@seen = {}
|
|
@@ -61,6 +65,17 @@ module Smplkit
|
|
|
61
65
|
end
|
|
62
66
|
end
|
|
63
67
|
|
|
68
|
+
def peek
|
|
69
|
+
@lock.synchronize { @pending.dup }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def commit(ids)
|
|
73
|
+
return if ids.nil? || ids.empty?
|
|
74
|
+
|
|
75
|
+
committed = ids.to_set
|
|
76
|
+
@lock.synchronize { @pending.reject! { |item| committed.include?(item["id"]) } }
|
|
77
|
+
end
|
|
78
|
+
|
|
64
79
|
def drain
|
|
65
80
|
@lock.synchronize do
|
|
66
81
|
batch = @pending
|
|
@@ -538,11 +538,24 @@ module Smplkit
|
|
|
538
538
|
|
|
539
539
|
def register(declaration)
|
|
540
540
|
@buffer.add(declaration)
|
|
541
|
-
|
|
541
|
+
return unless @buffer.pending_count >= Management::FLAG_BATCH_FLUSH_SIZE
|
|
542
|
+
|
|
543
|
+
begin
|
|
544
|
+
flush
|
|
545
|
+
rescue StandardError => e
|
|
546
|
+
Smplkit.debug("registration", "threshold flag flush failed: #{e.class}: #{e.message}")
|
|
547
|
+
end
|
|
542
548
|
end
|
|
543
549
|
|
|
550
|
+
# POST pending declarations to the bulk endpoint.
|
|
551
|
+
#
|
|
552
|
+
# Items remain in the buffer until the request succeeds, so a flush
|
|
553
|
+
# against an unhealthy service is automatically retried by the next
|
|
554
|
+
# +flush+ call (lazy +start+ retry, periodic background flush, or
|
|
555
|
+
# final flush on close). Raises on failure — callers decide whether
|
|
556
|
+
# to retry.
|
|
544
557
|
def flush
|
|
545
|
-
batch = @buffer.
|
|
558
|
+
batch = @buffer.peek
|
|
546
559
|
return if batch.empty?
|
|
547
560
|
|
|
548
561
|
flag_items = batch.map do |entry|
|
|
@@ -553,8 +566,11 @@ module Smplkit
|
|
|
553
566
|
end
|
|
554
567
|
body = SmplkitGeneratedClient::Flags::FlagBulkRequest.new(flags: flag_items)
|
|
555
568
|
ErrorMapping.call { @api.bulk_register_flags(body) }
|
|
556
|
-
|
|
557
|
-
|
|
569
|
+
@buffer.commit(batch.map { |b| b["id"] })
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def pending_count
|
|
573
|
+
@buffer.pending_count
|
|
558
574
|
end
|
|
559
575
|
|
|
560
576
|
def list
|