Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit f34f3a3

Browse files
committed
don't try to send more diagnostic events after an unrecoverable HTTP error
1 parent b953d6d commit f34f3a3

File tree

2 files changed

+54
-13
lines changed

2 files changed

+54
-13
lines changed

src/main/java/com/launchdarkly/sdk/server/DefaultEventProcessor.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ private EventDispatcher(
262262

263263
if (diagnosticAccumulator != null) {
264264
// Set up diagnostics
265-
this.sendDiagnosticTaskFactory = new SendDiagnosticTaskFactory(eventsConfig);
265+
this.sendDiagnosticTaskFactory = new SendDiagnosticTaskFactory(eventsConfig, this::handleResponse);
266266
sharedExecutor.submit(sendDiagnosticTaskFactory.createSendDiagnosticTask(diagnosticInitEvent));
267267
} else {
268268
sendDiagnosticTaskFactory = null;
@@ -334,6 +334,9 @@ private void runMainLoop(BlockingQueue<EventProcessorMessage> inbox,
334334
}
335335

336336
private void sendAndResetDiagnostics(EventBuffer outbox) {
337+
if (disabled.get()) {
338+
return;
339+
}
337340
long droppedEvents = outbox.getAndClearDroppedCount();
338341
// We pass droppedEvents and deduplicatedUsers as parameters here because they are updated frequently in the main loop so we want to avoid synchronization on them.
339342
DiagnosticEvent diagnosticEvent = diagnosticAccumulator.createEventAndReset(droppedEvents, deduplicatedUsers);
@@ -597,17 +600,26 @@ void stop() {
597600

598601
private static final class SendDiagnosticTaskFactory {
599602
private final EventsConfiguration eventsConfig;
603+
private final EventResponseListener eventResponseListener;
600604

601-
SendDiagnosticTaskFactory(EventsConfiguration eventsConfig) {
605+
SendDiagnosticTaskFactory(
606+
EventsConfiguration eventsConfig,
607+
EventResponseListener eventResponseListener
608+
) {
602609
this.eventsConfig = eventsConfig;
610+
this.eventResponseListener = eventResponseListener;
603611
}
604612

605613
Runnable createSendDiagnosticTask(final DiagnosticEvent diagnosticEvent) {
606614
return new Runnable() {
607615
@Override
608616
public void run() {
609617
String json = JsonHelpers.serialize(diagnosticEvent);
610-
eventsConfig.eventSender.sendEventData(EventDataKind.DIAGNOSTICS, json, 1, eventsConfig.eventsUri);
618+
EventSender.Result result = eventsConfig.eventSender.sendEventData(EventDataKind.DIAGNOSTICS,
619+
json, 1, eventsConfig.eventsUri);
620+
if (eventResponseListener != null) {
621+
eventResponseListener.handleResponse(result);
622+
}
611623
}
612624
};
613625
}

src/test/java/com/launchdarkly/sdk/server/DefaultEventProcessorDiagnosticsTest.java

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,31 @@ public void periodicDiagnosticEventGetsEventsInLastBatchAndDeduplicatedUsers() t
123123

124124
@Test
125125
public void periodicDiagnosticEventsAreSentAutomatically() throws Exception {
126-
// This test overrides the diagnostic recording interval to a small value and verifies that we see
127-
// at least one periodic event without having to force a send via ep.postDiagnostic().
128126
MockEventSender es = new MockEventSender();
129127
DiagnosticId diagnosticId = new DiagnosticId(SDK_KEY);
130128
ClientContext context = clientContext(SDK_KEY, LDConfig.DEFAULT);
131129
DiagnosticEvent.Init initEvent = new DiagnosticEvent.Init(0, diagnosticId, LDConfig.DEFAULT,
132130
context.getBasic(), context.getHttp());
133131
DiagnosticAccumulator diagnosticAccumulator = new DiagnosticAccumulator(diagnosticId);
134-
Duration briefPeriodicInterval = Duration.ofMillis(50);
135132

133+
EventsConfiguration eventsConfig = makeEventsConfigurationWithBriefDiagnosticInterval(es);
134+
135+
try (DefaultEventProcessor ep = new DefaultEventProcessor(eventsConfig, sharedExecutor, Thread.MAX_PRIORITY,
136+
diagnosticAccumulator, initEvent)) {
137+
// Ignore the initial diagnostic event
138+
es.awaitRequest();
139+
140+
MockEventSender.Params periodicReq = es.awaitRequest();
141+
142+
assertNotNull(periodicReq);
143+
DiagnosticEvent.Statistics statsEvent = gson.fromJson(periodicReq.data, DiagnosticEvent.Statistics.class);
144+
assertEquals("diagnostic", statsEvent.kind);
145+
}
146+
}
147+
148+
private EventsConfiguration makeEventsConfigurationWithBriefDiagnosticInterval(EventSender es) {
136149
// Can't use the regular config builder for this, because it will enforce a minimum flush interval
137-
EventsConfiguration eventsConfig = new EventsConfiguration(
150+
return new EventsConfiguration(
138151
false,
139152
100,
140153
es,
@@ -144,18 +157,34 @@ public void periodicDiagnosticEventsAreSentAutomatically() throws Exception {
144157
ImmutableSet.of(),
145158
100,
146159
Duration.ofSeconds(5),
147-
briefPeriodicInterval
160+
Duration.ofMillis(50)
148161
);
162+
}
163+
164+
@Test
165+
public void diagnosticEventsStopAfter401Error() throws Exception {
166+
// This is easier to test with a mock component than it would be in LDClientEndToEndTest, because
167+
// we don't have to worry about the latency of a real HTTP request which could allow the periodic
168+
// task to fire again before we received a response. In real life, that wouldn't matter because
169+
// the minimum diagnostic interval is so long, but in a test we need to be able to use a short
170+
// interval.
171+
MockEventSender es = new MockEventSender();
172+
es.result = new EventSender.Result(false, true, null); // mustShutdown=true; this is what would be returned for a 401 error
173+
174+
DiagnosticId diagnosticId = new DiagnosticId(SDK_KEY);
175+
ClientContext context = clientContext(SDK_KEY, LDConfig.DEFAULT);
176+
DiagnosticEvent.Init initEvent = new DiagnosticEvent.Init(0, diagnosticId, LDConfig.DEFAULT,
177+
context.getBasic(), context.getHttp());
178+
DiagnosticAccumulator diagnosticAccumulator = new DiagnosticAccumulator(diagnosticId);
179+
180+
EventsConfiguration eventsConfig = makeEventsConfigurationWithBriefDiagnosticInterval(es);
181+
149182
try (DefaultEventProcessor ep = new DefaultEventProcessor(eventsConfig, sharedExecutor, Thread.MAX_PRIORITY,
150183
diagnosticAccumulator, initEvent)) {
151184
// Ignore the initial diagnostic event
152185
es.awaitRequest();
153186

154-
MockEventSender.Params periodicReq = es.awaitRequest();
155-
156-
assertNotNull(periodicReq);
157-
DiagnosticEvent.Statistics statsEvent = gson.fromJson(periodicReq.data, DiagnosticEvent.Statistics.class);
158-
assertEquals("diagnostic", statsEvent.kind);
187+
es.expectNoRequests(Duration.ofMillis(100));
159188
}
160189
}
161190

0 commit comments

Comments
 (0)