@@ -18,6 +18,7 @@ import (
18
18
"go.uber.org/atomic"
19
19
"google.golang.org/grpc"
20
20
21
+ "github.com/grafana/loki/v3/pkg/bloombuild/planner/plannertest"
21
22
"github.com/grafana/loki/v3/pkg/bloombuild/protos"
22
23
"github.com/grafana/loki/v3/pkg/storage"
23
24
v1 "github.com/grafana/loki/v3/pkg/storage/bloom/v1"
@@ -28,10 +29,7 @@ import (
28
29
"github.com/grafana/loki/v3/pkg/storage/types"
29
30
)
30
31
31
- func Test_BuilderLoop (t * testing.T ) {
32
- logger := log .NewNopLogger ()
33
- //logger := log.NewLogfmtLogger(os.Stdout)
34
-
32
+ func setupBuilder (t * testing.T , plannerAddr string , limits Limits , logger log.Logger ) * Builder {
35
33
schemaCfg := config.SchemaConfig {
36
34
Configs : []config.PeriodConfig {
37
35
{
@@ -64,22 +62,8 @@ func Test_BuilderLoop(t *testing.T) {
64
62
},
65
63
}
66
64
67
- tasks := make ([]* protos.ProtoTask , 256 )
68
- for i := range tasks {
69
- tasks [i ] = & protos.ProtoTask {
70
- Id : fmt .Sprintf ("task-%d" , i ),
71
- }
72
- }
73
-
74
- server , err := newFakePlannerServer (tasks )
75
- require .NoError (t , err )
76
-
77
- // Start the server so the builder can connect and receive tasks.
78
- server .Start ()
79
-
80
- limits := fakeLimits {}
81
65
cfg := Config {
82
- PlannerAddress : server . Addr () ,
66
+ PlannerAddress : plannerAddr ,
83
67
BackoffConfig : backoff.Config {
84
68
MinBackoff : 1 * time .Second ,
85
69
MaxBackoff : 10 * time .Second ,
@@ -88,8 +72,48 @@ func Test_BuilderLoop(t *testing.T) {
88
72
}
89
73
flagext .DefaultValues (& cfg .GrpcConfig )
90
74
91
- builder , err := New (cfg , limits , schemaCfg , storageCfg , storage .NewClientMetrics (), nil , fakeBloomStore {}, logger , prometheus .DefaultRegisterer , nil )
75
+ metrics := storage .NewClientMetrics ()
76
+ metrics .Unregister ()
77
+
78
+ builder , err := New (cfg , limits , schemaCfg , storageCfg , metrics , nil , fakeBloomStore {}, logger , prometheus .NewPedanticRegistry (), nil )
79
+ require .NoError (t , err )
80
+
81
+ return builder
82
+ }
83
+
84
+ func createTasks (n int ) []* protos.ProtoTask {
85
+ tasks := make ([]* protos.ProtoTask , n )
86
+ for i := range tasks {
87
+ tasks [i ] = protos .NewTask (
88
+ plannertest .TestTable ,
89
+ "fake" ,
90
+ v1 .NewBounds (model .Fingerprint (i ), model .Fingerprint (i + 10 )),
91
+ plannertest .TsdbID (1 ),
92
+ []protos.Gap {
93
+ {
94
+ Bounds : v1 .NewBounds (model .Fingerprint (i + 1 ), model .Fingerprint (i + 2 )),
95
+ },
96
+ {
97
+ Bounds : v1 .NewBounds (model .Fingerprint (i + 3 ), model .Fingerprint (i + 9 )),
98
+ },
99
+ },
100
+ ).ToProtoTask ()
101
+ }
102
+ return tasks
103
+ }
104
+
105
+ func Test_BuilderLoop (t * testing.T ) {
106
+ logger := log .NewNopLogger ()
107
+ //logger := log.NewLogfmtLogger(os.Stdout)
108
+
109
+ tasks := createTasks (256 )
110
+ server , err := newFakePlannerServer (tasks )
92
111
require .NoError (t , err )
112
+
113
+ // Start the server so the builder can connect and receive tasks.
114
+ server .Start ()
115
+
116
+ builder := setupBuilder (t , server .Addr (), fakeLimits {}, logger )
93
117
t .Cleanup (func () {
94
118
err = services .StopAndAwaitTerminated (context .Background (), builder )
95
119
require .NoError (t , err )
@@ -128,9 +152,71 @@ func Test_BuilderLoop(t *testing.T) {
128
152
require .True (t , server .shutdownCalled )
129
153
}
130
154
155
+ func Test_BuilderLoop_Timeout (t * testing.T ) {
156
+ for _ , tc := range []struct {
157
+ name string
158
+ timeout time.Duration
159
+ allTasksSucceed bool
160
+ }{
161
+ {
162
+ name : "no timeout configured" ,
163
+ timeout : 0 ,
164
+ allTasksSucceed : true ,
165
+ },
166
+ {
167
+ name : "long enough timeout" ,
168
+ timeout : 15 * time .Minute ,
169
+ allTasksSucceed : true ,
170
+ },
171
+ {
172
+ name : "task times out" ,
173
+ timeout : 1 * time .Nanosecond , // Pretty much immediately.
174
+ allTasksSucceed : false ,
175
+ },
176
+ } {
177
+ t .Run (tc .name , func (t * testing.T ) {
178
+ logger := log .NewNopLogger ()
179
+ //logger := log.NewLogfmtLogger(os.Stdout)
180
+
181
+ tasks := createTasks (256 )
182
+ server , err := newFakePlannerServer (tasks )
183
+ require .NoError (t , err )
184
+
185
+ // Start the server so the builder can connect and receive tasks.
186
+ server .Start ()
187
+
188
+ limits := fakeLimits {
189
+ taskTimout : tc .timeout ,
190
+ }
191
+ builder := setupBuilder (t , server .Addr (), limits , logger )
192
+ t .Cleanup (func () {
193
+ err = services .StopAndAwaitTerminated (context .Background (), builder )
194
+ require .NoError (t , err )
195
+
196
+ server .Stop ()
197
+ })
198
+
199
+ err = services .StartAndAwaitRunning (context .Background (), builder )
200
+ require .NoError (t , err )
201
+
202
+ require .Eventually (t , func () bool {
203
+ return server .CompletedTasks () >= len (tasks )
204
+ }, 30 * time .Second , 500 * time .Millisecond )
205
+
206
+ erroredTasks := server .ErroredTasks ()
207
+ if tc .allTasksSucceed {
208
+ require .Equal (t , 0 , erroredTasks )
209
+ } else {
210
+ require .Equal (t , len (tasks ), erroredTasks )
211
+ }
212
+ })
213
+ }
214
+ }
215
+
131
216
type fakePlannerServer struct {
132
217
tasks []* protos.ProtoTask
133
218
completedTasks atomic.Int64
219
+ erroredTasks atomic.Int64
134
220
shutdownCalled bool
135
221
136
222
listenAddr string
@@ -198,11 +284,18 @@ func (f *fakePlannerServer) BuilderLoop(srv protos.PlannerForBuilder_BuilderLoop
198
284
if err := srv .Send (& protos.PlannerToBuilder {Task : task }); err != nil {
199
285
return fmt .Errorf ("failed to send task: %w" , err )
200
286
}
201
- if _ , err := srv .Recv (); err != nil {
287
+
288
+ result , err := srv .Recv ()
289
+ if err != nil {
202
290
return fmt .Errorf ("failed to receive task response: %w" , err )
203
291
}
204
- time . Sleep ( 10 * time . Millisecond ) // Simulate task processing time to add some latency.
292
+
205
293
f .completedTasks .Inc ()
294
+ if result .Result .Error != "" {
295
+ f .erroredTasks .Inc ()
296
+ }
297
+
298
+ time .Sleep (10 * time .Millisecond ) // Simulate task processing time to add some latency.
206
299
}
207
300
208
301
// No more tasks. Wait until shutdown.
@@ -214,32 +307,36 @@ func (f *fakePlannerServer) CompletedTasks() int {
214
307
return int (f .completedTasks .Load ())
215
308
}
216
309
310
+ func (f * fakePlannerServer ) ErroredTasks () int {
311
+ return int (f .erroredTasks .Load ())
312
+ }
313
+
217
314
func (f * fakePlannerServer ) NotifyBuilderShutdown (_ context.Context , _ * protos.NotifyBuilderShutdownRequest ) (* protos.NotifyBuilderShutdownResponse , error ) {
218
315
f .shutdownCalled = true
219
316
return & protos.NotifyBuilderShutdownResponse {}, nil
220
317
}
221
318
222
319
type fakeLimits struct {
320
+ Limits
321
+ taskTimout time.Duration
223
322
}
224
323
225
- func (f fakeLimits ) BloomBlockEncoding (_ string ) string {
226
- panic ("implement me" )
227
- }
228
-
229
- func (f fakeLimits ) BloomNGramLength (_ string ) int {
230
- panic ("implement me" )
231
- }
324
+ var _ Limits = fakeLimits {}
232
325
233
- func (f fakeLimits ) BloomNGramSkip (_ string ) int {
234
- panic ( "implement me" )
326
+ func (f fakeLimits ) BloomBlockEncoding (_ string ) string {
327
+ return "none"
235
328
}
236
329
237
330
func (f fakeLimits ) BloomMaxBlockSize (_ string ) int {
238
- panic ( "implement me" )
331
+ return 0
239
332
}
240
333
241
334
func (f fakeLimits ) BloomMaxBloomSize (_ string ) int {
242
- panic ("implement me" )
335
+ return 0
336
+ }
337
+
338
+ func (f fakeLimits ) BuilderResponseTimeout (_ string ) time.Duration {
339
+ return f .taskTimout
243
340
}
244
341
245
342
type fakeBloomStore struct {
@@ -250,6 +347,26 @@ func (f fakeBloomStore) BloomMetrics() *v1.Metrics {
250
347
return nil
251
348
}
252
349
350
+ func (f fakeBloomStore ) Client (_ model.Time ) (bloomshipper.Client , error ) {
351
+ return fakeBloomClient {}, nil
352
+ }
353
+
354
+ func (f fakeBloomStore ) Fetcher (_ model.Time ) (* bloomshipper.Fetcher , error ) {
355
+ return & bloomshipper.Fetcher {}, nil
356
+ }
357
+
358
+ type fakeBloomClient struct {
359
+ bloomshipper.Client
360
+ }
361
+
362
+ func (f fakeBloomClient ) PutBlock (_ context.Context , _ bloomshipper.Block ) error {
363
+ return nil
364
+ }
365
+
366
+ func (f fakeBloomClient ) PutMeta (_ context.Context , _ bloomshipper.Meta ) error {
367
+ return nil
368
+ }
369
+
253
370
func parseDayTime (s string ) config.DayTime {
254
371
t , err := time .Parse ("2006-01-02" , s )
255
372
if err != nil {
0 commit comments