@@ -40,22 +40,24 @@ type batchSender struct {
40
40
41
41
logger * zap.Logger
42
42
43
- shutdownCh chan struct {}
44
- stopped * atomic.Bool
43
+ shutdownCh chan struct {}
44
+ shutdownCompleteCh chan struct {}
45
+ stopped * atomic.Bool
45
46
}
46
47
47
48
// newBatchSender returns a new batch consumer component.
48
49
func newBatchSender (cfg exporterbatcher.Config , set exporter.CreateSettings ,
49
50
mf exporterbatcher.BatchMergeFunc [Request ], msf exporterbatcher.BatchMergeSplitFunc [Request ]) * batchSender {
50
51
bs := & batchSender {
51
- activeBatch : newEmptyBatch (),
52
- cfg : cfg ,
53
- logger : set .Logger ,
54
- mergeFunc : mf ,
55
- mergeSplitFunc : msf ,
56
- shutdownCh : make (chan struct {}),
57
- stopped : & atomic.Bool {},
58
- resetTimerCh : make (chan struct {}),
52
+ activeBatch : newEmptyBatch (),
53
+ cfg : cfg ,
54
+ logger : set .Logger ,
55
+ mergeFunc : mf ,
56
+ mergeSplitFunc : msf ,
57
+ shutdownCh : make (chan struct {}),
58
+ shutdownCompleteCh : make (chan struct {}),
59
+ stopped : & atomic.Bool {},
60
+ resetTimerCh : make (chan struct {}),
59
61
}
60
62
return bs
61
63
}
@@ -66,14 +68,19 @@ func (bs *batchSender) Start(_ context.Context, _ component.Host) error {
66
68
for {
67
69
select {
68
70
case <- bs .shutdownCh :
69
- bs .mu .Lock ()
70
- if bs .activeBatch .request != nil {
71
- bs .exportActiveBatch ()
71
+ // There is a minimal chance that another request is added after the shutdown signal.
72
+ // This loop will handle that case.
73
+ for bs .activeRequests .Load () > 0 {
74
+ bs .mu .Lock ()
75
+ if bs .activeBatch .request != nil {
76
+ bs .exportActiveBatch ()
77
+ }
78
+ bs .mu .Unlock ()
72
79
}
73
- bs .mu .Unlock ()
74
80
if ! timer .Stop () {
75
81
<- timer .C
76
82
}
83
+ close (bs .shutdownCompleteCh )
77
84
return
78
85
case <- timer .C :
79
86
bs .mu .Lock ()
@@ -118,6 +125,12 @@ func (bs *batchSender) exportActiveBatch() {
118
125
bs .activeBatch = newEmptyBatch ()
119
126
}
120
127
128
+ func (bs * batchSender ) resetTimer () {
129
+ if ! bs .stopped .Load () {
130
+ bs .resetTimerCh <- struct {}{}
131
+ }
132
+ }
133
+
121
134
// isActiveBatchReady returns true if the active batch is ready to be exported.
122
135
// The batch is ready if it has reached the minimum size or the concurrency limit is reached.
123
136
// Caller must hold the lock.
@@ -154,7 +167,7 @@ func (bs *batchSender) sendMergeSplitBatch(ctx context.Context, req Request) err
154
167
batch := bs .activeBatch
155
168
if bs .isActiveBatchReady () || len (reqs ) > 1 {
156
169
bs .exportActiveBatch ()
157
- bs .resetTimerCh <- struct {}{}
170
+ bs .resetTimer ()
158
171
}
159
172
bs .mu .Unlock ()
160
173
<- batch .done
@@ -194,7 +207,7 @@ func (bs *batchSender) sendMergeBatch(ctx context.Context, req Request) error {
194
207
batch := bs .activeBatch
195
208
if bs .isActiveBatchReady () {
196
209
bs .exportActiveBatch ()
197
- bs .resetTimerCh <- struct {}{}
210
+ bs .resetTimer ()
198
211
}
199
212
bs .mu .Unlock ()
200
213
<- batch .done
@@ -215,9 +228,6 @@ func (bs *batchSender) updateActiveBatch(ctx context.Context, req Request) {
215
228
func (bs * batchSender ) Shutdown (context.Context ) error {
216
229
bs .stopped .Store (true )
217
230
close (bs .shutdownCh )
218
- // Wait for the active requests to finish.
219
- for bs .activeRequests .Load () > 0 {
220
- time .Sleep (10 * time .Millisecond )
221
- }
231
+ <- bs .shutdownCompleteCh
222
232
return nil
223
233
}
0 commit comments