You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-06-27 00:21:15 +02:00
Fix BatchSpanProcessor.Shutdown to wait until all spans are processed (#766)
* Fix BatchSpanProcessor.Shutdown to wait until all spans are processed Currently it exits too soon - before drainQueue is finished * Check bsp.stopCh to reliably drop span when batcher is stopped * Enable tests * Always use WithBlocking Co-authored-by: Joshua MacDonald <jmacd@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
c58680a772
commit
7ebd7b5ffa
@ -105,9 +105,10 @@ func NewBatchSpanProcessor(e export.SpanBatcher, opts ...BatchSpanProcessorOptio
|
|||||||
queue: make(chan *export.SpanData, o.MaxQueueSize),
|
queue: make(chan *export.SpanData, o.MaxQueueSize),
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
bsp.stopWait.Add(1)
|
|
||||||
|
|
||||||
|
bsp.stopWait.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
defer bsp.stopWait.Done()
|
||||||
bsp.processQueue()
|
bsp.processQueue()
|
||||||
bsp.drainQueue()
|
bsp.drainQueue()
|
||||||
}()
|
}()
|
||||||
@ -130,8 +131,6 @@ func (bsp *BatchSpanProcessor) Shutdown() {
|
|||||||
bsp.stopOnce.Do(func() {
|
bsp.stopOnce.Do(func() {
|
||||||
close(bsp.stopCh)
|
close(bsp.stopCh)
|
||||||
bsp.stopWait.Wait()
|
bsp.stopWait.Wait()
|
||||||
close(bsp.queue)
|
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +172,6 @@ func (bsp *BatchSpanProcessor) exportSpans() {
|
|||||||
// is shut down. It calls the exporter in batches of up to MaxExportBatchSize
|
// is shut down. It calls the exporter in batches of up to MaxExportBatchSize
|
||||||
// waiting up to BatchTimeout to form a batch.
|
// waiting up to BatchTimeout to form a batch.
|
||||||
func (bsp *BatchSpanProcessor) processQueue() {
|
func (bsp *BatchSpanProcessor) processQueue() {
|
||||||
defer bsp.stopWait.Done()
|
|
||||||
defer bsp.timer.Stop()
|
defer bsp.timer.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -197,13 +195,22 @@ func (bsp *BatchSpanProcessor) processQueue() {
|
|||||||
// drainQueue awaits the any caller that had added to bsp.stopWait
|
// drainQueue awaits the any caller that had added to bsp.stopWait
|
||||||
// to finish the enqueue, then exports the final batch.
|
// to finish the enqueue, then exports the final batch.
|
||||||
func (bsp *BatchSpanProcessor) drainQueue() {
|
func (bsp *BatchSpanProcessor) drainQueue() {
|
||||||
for sd := range bsp.queue {
|
for {
|
||||||
bsp.batch = append(bsp.batch, sd)
|
select {
|
||||||
if len(bsp.batch) == bsp.o.MaxExportBatchSize {
|
case sd := <-bsp.queue:
|
||||||
bsp.exportSpans()
|
if sd == nil {
|
||||||
|
bsp.exportSpans()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bsp.batch = append(bsp.batch, sd)
|
||||||
|
if len(bsp.batch) == bsp.o.MaxExportBatchSize {
|
||||||
|
bsp.exportSpans()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
close(bsp.queue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bsp.exportSpans()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsp *BatchSpanProcessor) enqueue(sd *export.SpanData) {
|
func (bsp *BatchSpanProcessor) enqueue(sd *export.SpanData) {
|
||||||
@ -226,17 +233,19 @@ func (bsp *BatchSpanProcessor) enqueue(sd *export.SpanData) {
|
|||||||
panic(x)
|
panic(x)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-bsp.stopCh:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
if bsp.o.BlockOnQueueFull {
|
if bsp.o.BlockOnQueueFull {
|
||||||
select {
|
bsp.queue <- sd
|
||||||
case bsp.queue <- sd:
|
|
||||||
case <-bsp.stopCh:
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case bsp.queue <- sd:
|
case bsp.queue <- sd:
|
||||||
case <-bsp.stopCh:
|
|
||||||
default:
|
default:
|
||||||
atomic.AddUint32(&bsp.dropped, 1)
|
atomic.AddUint32(&bsp.dropped, 1)
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,6 @@ func TestNewBatchSpanProcessorWithOptions(t *testing.T) {
|
|||||||
sdktrace.WithBatchTimeout(schDelay),
|
sdktrace.WithBatchTimeout(schDelay),
|
||||||
sdktrace.WithMaxQueueSize(200),
|
sdktrace.WithMaxQueueSize(200),
|
||||||
sdktrace.WithMaxExportBatchSize(20),
|
sdktrace.WithMaxExportBatchSize(20),
|
||||||
sdktrace.WithBlocking(),
|
|
||||||
},
|
},
|
||||||
wantNumSpans: 205,
|
wantNumSpans: 205,
|
||||||
wantBatchCount: 11,
|
wantBatchCount: 11,
|
||||||
@ -139,7 +138,6 @@ func TestNewBatchSpanProcessorWithOptions(t *testing.T) {
|
|||||||
o: []sdktrace.BatchSpanProcessorOption{
|
o: []sdktrace.BatchSpanProcessorOption{
|
||||||
sdktrace.WithBatchTimeout(schDelay),
|
sdktrace.WithBatchTimeout(schDelay),
|
||||||
sdktrace.WithMaxExportBatchSize(200),
|
sdktrace.WithMaxExportBatchSize(200),
|
||||||
sdktrace.WithBlocking(),
|
|
||||||
},
|
},
|
||||||
wantNumSpans: 2000,
|
wantNumSpans: 2000,
|
||||||
wantBatchCount: 10,
|
wantBatchCount: 10,
|
||||||
@ -162,18 +160,26 @@ func TestNewBatchSpanProcessorWithOptions(t *testing.T) {
|
|||||||
|
|
||||||
tp.UnregisterSpanProcessor(ssp)
|
tp.UnregisterSpanProcessor(ssp)
|
||||||
|
|
||||||
// TODO(https://github.com/open-telemetry/opentelemetry-go/issues/741)
|
gotNumOfSpans := te.len()
|
||||||
// Restore some sort of test here.
|
if option.wantNumSpans != gotNumOfSpans {
|
||||||
_ = option.wantNumSpans
|
t.Errorf("number of exported span: got %+v, want %+v\n",
|
||||||
_ = option.wantBatchCount
|
gotNumOfSpans, option.wantNumSpans)
|
||||||
_ = te.len() // gotNumOfSpans
|
}
|
||||||
_ = te.getBatchCount() // gotBatchCount
|
|
||||||
|
gotBatchCount := te.getBatchCount()
|
||||||
|
if gotBatchCount < option.wantBatchCount {
|
||||||
|
t.Errorf("number batches: got %+v, want >= %+v\n",
|
||||||
|
gotBatchCount, option.wantBatchCount)
|
||||||
|
t.Errorf("Batches %v\n", te.sizes)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAndRegisterBatchSP(t *testing.T, option testOption, te *testBatchExporter) *sdktrace.BatchSpanProcessor {
|
func createAndRegisterBatchSP(t *testing.T, option testOption, te *testBatchExporter) *sdktrace.BatchSpanProcessor {
|
||||||
ssp, err := sdktrace.NewBatchSpanProcessor(te, option.o...)
|
// Always use blocking queue to avoid flaky tests.
|
||||||
|
options := append(option.o, sdktrace.WithBlocking())
|
||||||
|
ssp, err := sdktrace.NewBatchSpanProcessor(te, options...)
|
||||||
if ssp == nil {
|
if ssp == nil {
|
||||||
t.Errorf("%s: Error creating new instance of BatchSpanProcessor, error: %v\n", option.name, err)
|
t.Errorf("%s: Error creating new instance of BatchSpanProcessor, error: %v\n", option.name, err)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user