Skip to content

Commit 3c7face

Browse files
matej-gMrAlias
andauthored
Add ExportTimeout option to batch span processor (#1755)
* Add ExportTimeout option * Adjust tests * Update CHANGELOG * Beef up the exporter timeout test * Beef up exporter test - attempt #2 Co-authored-by: Tyler Yahn <[email protected]>
1 parent c6b92d5 commit 3c7face

File tree

3 files changed

+59
-9
lines changed

3 files changed

+59
-9
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1010

1111
### Added
1212

13+
- Option `ExportTimeout` was added to batch span processor. (#1755)
1314
- Adds semantic conventions for exceptions. (#1492)
1415
- Added support for configuring OTLP/HTTP Endpoints, Headers, Compression and Timeout via the Environment Variables. (#1758)
1516
- `OTEL_EXPORTER_OTLP_ENDPOINT`

sdk/trace/batch_span_processor.go

+19
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
const (
2929
DefaultMaxQueueSize = 2048
3030
DefaultBatchTimeout = 5000 * time.Millisecond
31+
DefaultExportTimeout = 30000 * time.Millisecond
3132
DefaultMaxExportBatchSize = 512
3233
)
3334

@@ -44,6 +45,11 @@ type BatchSpanProcessorOptions struct {
4445
// The default value of BatchTimeout is 5000 msec.
4546
BatchTimeout time.Duration
4647

48+
// ExportTimeout specifies the maximum duration for exporting spans. If the timeout
49+
// is reached, the export will be cancelled.
50+
// The default value of ExportTimeout is 30000 msec.
51+
ExportTimeout time.Duration
52+
4753
// MaxExportBatchSize is the maximum number of spans to process in a single batch.
4854
// If there are more than one batch worth of spans then it processes multiple batches
4955
// of spans one batch after the other without any delay.
@@ -83,6 +89,7 @@ var _ SpanProcessor = (*batchSpanProcessor)(nil)
8389
func NewBatchSpanProcessor(exporter export.SpanExporter, options ...BatchSpanProcessorOption) SpanProcessor {
8490
o := BatchSpanProcessorOptions{
8591
BatchTimeout: DefaultBatchTimeout,
92+
ExportTimeout: DefaultExportTimeout,
8693
MaxQueueSize: DefaultMaxQueueSize,
8794
MaxExportBatchSize: DefaultMaxExportBatchSize,
8895
}
@@ -185,6 +192,12 @@ func WithBatchTimeout(delay time.Duration) BatchSpanProcessorOption {
185192
}
186193
}
187194

195+
func WithExportTimeout(timeout time.Duration) BatchSpanProcessorOption {
196+
return func(o *BatchSpanProcessorOptions) {
197+
o.ExportTimeout = timeout
198+
}
199+
}
200+
188201
func WithBlocking() BatchSpanProcessorOption {
189202
return func(o *BatchSpanProcessorOptions) {
190203
o.BlockOnQueueFull = true
@@ -198,6 +211,12 @@ func (bsp *batchSpanProcessor) exportSpans(ctx context.Context) error {
198211
bsp.batchMutex.Lock()
199212
defer bsp.batchMutex.Unlock()
200213

214+
if bsp.o.ExportTimeout > 0 {
215+
var cancel context.CancelFunc
216+
ctx, cancel = context.WithTimeout(ctx, bsp.o.ExportTimeout)
217+
defer cancel()
218+
}
219+
201220
if len(bsp.batch) > 0 {
202221
if err := bsp.e.ExportSpans(ctx, bsp.batch); err != nil {
203222
return err

sdk/trace/batch_span_processor_test.go

+39-9
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,23 @@ type testBatchExporter struct {
3636
sizes []int
3737
batchCount int
3838
shutdownCount int
39+
delay time.Duration
40+
err error
3941
}
4042

4143
func (t *testBatchExporter) ExportSpans(ctx context.Context, ss []*export.SpanSnapshot) error {
4244
t.mu.Lock()
4345
defer t.mu.Unlock()
4446

47+
time.Sleep(t.delay)
48+
49+
select {
50+
case <-ctx.Done():
51+
t.err = ctx.Err()
52+
return ctx.Err()
53+
default:
54+
}
55+
4556
t.spans = append(t.spans, ss...)
4657
t.sizes = append(t.sizes, len(ss))
4758
t.batchCount++
@@ -88,23 +99,35 @@ func TestNewBatchSpanProcessorWithNilExporter(t *testing.T) {
8899
}
89100

90101
type testOption struct {
91-
name string
92-
o []sdktrace.BatchSpanProcessorOption
93-
wantNumSpans int
94-
wantBatchCount int
95-
genNumSpans int
96-
parallel bool
102+
name string
103+
o []sdktrace.BatchSpanProcessorOption
104+
wantNumSpans int
105+
wantBatchCount int
106+
wantExportTimeout bool
107+
genNumSpans int
108+
delayExportBy time.Duration
109+
parallel bool
97110
}
98111

99112
func TestNewBatchSpanProcessorWithOptions(t *testing.T) {
100113
schDelay := 200 * time.Millisecond
114+
exportTimeout := time.Millisecond
101115
options := []testOption{
102116
{
103117
name: "default BatchSpanProcessorOptions",
104118
wantNumSpans: 2053,
105119
wantBatchCount: 4,
106120
genNumSpans: 2053,
107121
},
122+
{
123+
name: "non-default ExportTimeout",
124+
o: []sdktrace.BatchSpanProcessorOption{
125+
sdktrace.WithExportTimeout(exportTimeout),
126+
},
127+
wantExportTimeout: true,
128+
genNumSpans: 2053,
129+
delayExportBy: 2 * exportTimeout, // to ensure export timeout
130+
},
108131
{
109132
name: "non-default BatchTimeout",
110133
o: []sdktrace.BatchSpanProcessorOption{
@@ -171,7 +194,9 @@ func TestNewBatchSpanProcessorWithOptions(t *testing.T) {
171194
}
172195
for _, option := range options {
173196
t.Run(option.name, func(t *testing.T) {
174-
te := testBatchExporter{}
197+
te := testBatchExporter{
198+
delay: option.delayExportBy,
199+
}
175200
tp := basicTracerProvider(t)
176201
ssp := createAndRegisterBatchSP(option, &te)
177202
if ssp == nil {
@@ -185,17 +210,22 @@ func TestNewBatchSpanProcessorWithOptions(t *testing.T) {
185210
tp.UnregisterSpanProcessor(ssp)
186211

187212
gotNumOfSpans := te.len()
188-
if option.wantNumSpans != gotNumOfSpans {
213+
if option.wantNumSpans > 0 && option.wantNumSpans != gotNumOfSpans {
189214
t.Errorf("number of exported span: got %+v, want %+v\n",
190215
gotNumOfSpans, option.wantNumSpans)
191216
}
192217

193218
gotBatchCount := te.getBatchCount()
194-
if gotBatchCount < option.wantBatchCount {
219+
if option.wantBatchCount > 0 && gotBatchCount < option.wantBatchCount {
195220
t.Errorf("number batches: got %+v, want >= %+v\n",
196221
gotBatchCount, option.wantBatchCount)
197222
t.Errorf("Batches %v\n", te.sizes)
198223
}
224+
225+
if option.wantExportTimeout && te.err != context.DeadlineExceeded {
226+
t.Errorf("context deadline: got err %+v, want %+v\n",
227+
te.err, context.DeadlineExceeded)
228+
}
199229
})
200230
}
201231
}

0 commit comments

Comments
 (0)