-
Notifications
You must be signed in to change notification settings - Fork 231
Handle full queue in RemoteReporter #180
Changes from all commits
8242beb
fa09ac6
4952d49
e34f389
569807c
9257c14
e3653d1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,8 +22,11 @@ | |
|
||
package com.uber.jaeger.reporters; | ||
|
||
import static org.hamcrest.CoreMatchers.anyOf; | ||
import static org.hamcrest.CoreMatchers.equalTo; | ||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertFalse; | ||
import static org.junit.Assert.assertThat; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
import com.uber.jaeger.Span; | ||
|
@@ -32,7 +35,10 @@ | |
import com.uber.jaeger.metrics.Metrics; | ||
import com.uber.jaeger.metrics.StatsFactoryImpl; | ||
import com.uber.jaeger.samplers.ConstSampler; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.CyclicBarrier; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
|
@@ -62,7 +68,7 @@ public void setUp() throws Exception { | |
public void testRemoteReporterReport() throws Exception { | ||
Span span = (Span) tracer.buildSpan("raza").start(); | ||
reporter.report(span); | ||
Thread.sleep(5); | ||
Thread.sleep(50); | ||
List<com.uber.jaeger.thriftjava.Span> received = sender.getReceived(); | ||
|
||
assertEquals(received.size(), 1); | ||
|
@@ -103,4 +109,115 @@ public void testRemoteReporterFlushTimerThread() throws Exception { | |
} | ||
assertFalse(flushTimerThreadCount == 0); | ||
} | ||
|
||
// Starts a number of threads. Each can fill the queue on its own, so they will exceed its | ||
// capacity many times over | ||
@Test | ||
public void testReportDoesntThrowWhenQueueFull() throws Exception { | ||
final AtomicBoolean exceptionWasThrown = new AtomicBoolean(false); | ||
|
||
int threadsCount = 10; | ||
final CyclicBarrier barrier = new CyclicBarrier(threadsCount); | ||
List<Thread> threads = new ArrayList<>(); | ||
for (int i = 0; i < threadsCount; i++) { | ||
Thread t = createSpanReportingThread(exceptionWasThrown, barrier); | ||
threads.add(t); | ||
t.start(); | ||
} | ||
|
||
for (Thread t : threads) { | ||
t.join(); | ||
} | ||
|
||
assertFalse(exceptionWasThrown.get()); | ||
} | ||
|
||
private Thread createSpanReportingThread(final AtomicBoolean exceptionWasThrown, | ||
final CyclicBarrier barrier) { | ||
return new Thread(new Runnable() { | ||
@Override | ||
public void run() { | ||
for (int x = 0; x < maxQueueSize; x++) { | ||
try { | ||
barrier.await(); | ||
reporter.report(newSpan()); | ||
} catch (Throwable e) { | ||
e.printStackTrace(); | ||
exceptionWasThrown.set(true); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
|
||
@Test | ||
public void testAppendWhenQueueFull() { | ||
// change sender to blocking mode | ||
sender.permitAppend(0); | ||
|
||
for (int i = 0; i < maxQueueSize; i++) { | ||
reporter.report(newSpan()); | ||
} | ||
|
||
// When: at this point the queue is full or there is one slot empty (if the worker thread has | ||
// already picked up some command). We add two spans to make sure that we overfill the queue | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the workers are still reading from the queue, then it looks like you have a race condition and no guarantee that the next two commands would actually cause a queue overflow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's why I changed InMemorySender to become blocking:
Thanks to this nothing is processing the queue - QueueProcessor picks only 1 AppendCommand and blocks on the append call.
Point 2 sometimes might not happen (due to scheduling) - then both span from points 3) and 4) are dropped. I tried to come with some simple way of testing various cases without possibility of race conditions - adding that semaphore/permits to InMemorySender was the simplest solution I could find. |
||
reporter.report(newSpan()); | ||
reporter.report(newSpan()); | ||
|
||
// Then: one or both spans should be dropped | ||
Long droppedCount = metricsReporter.counters.get("jaeger.spans.state=dropped"); | ||
assertThat(droppedCount, anyOf(equalTo(1L), equalTo(2L))); | ||
} | ||
|
||
@Test | ||
public void testCloseWhenQueueFull() { | ||
// change sender to blocking mode | ||
sender.permitAppend(0); | ||
|
||
// fill the queue | ||
for (int i = 0; i < maxQueueSize + 10; i++) { | ||
reporter.report(newSpan()); | ||
} | ||
|
||
reporter.close(); | ||
|
||
// expect no exception thrown | ||
} | ||
|
||
@Test | ||
public void testFlushWhenQueueFull() { | ||
// change sender to blocking mode | ||
sender.permitAppend(0); | ||
|
||
// fill the queue | ||
for (int i = 0; i < maxQueueSize + 10; i++) { | ||
reporter.report(newSpan()); | ||
} | ||
|
||
((RemoteReporter) reporter).flush(); | ||
|
||
// expect no exception thrown | ||
} | ||
|
||
@Test | ||
public void testFlushUpdatesQueueLength() throws Exception { | ||
// change sender to blocking mode | ||
sender.permitAppend(0); | ||
RemoteReporter remoteReporter = (RemoteReporter) reporter; | ||
remoteReporter.flush(); | ||
|
||
for (int i = 0; i < 10; i++) { | ||
reporter.report(newSpan()); | ||
} | ||
|
||
assertEquals(0, metricsReporter.gauges.get("jaeger.reporter-queue").longValue()); | ||
|
||
remoteReporter.flush(); | ||
|
||
assertTrue(metricsReporter.gauges.get("jaeger.reporter-queue") > 5); | ||
} | ||
|
||
private Span newSpan() { | ||
return (Span) tracer.buildSpan("x").start(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I increased it because it was failing every time on my laptop. There's already a PR to make it right: #177