@@ -10,9 +10,11 @@ import (
10
10
"github.com/grafana/loki/v3/pkg/blockbuilder/types"
11
11
)
12
12
13
+ var testQueueCfg = JobQueueConfig {}
14
+
13
15
func TestJobQueue_SyncJob (t * testing.T ) {
14
16
t .Run ("non-existent to in-progress" , func (t * testing.T ) {
15
- q := NewJobQueue (log .NewNopLogger (), nil )
17
+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
16
18
job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
17
19
jobID := job .ID ()
18
20
@@ -29,7 +31,7 @@ func TestJobQueue_SyncJob(t *testing.T) {
29
31
})
30
32
31
33
t .Run ("pending to in-progress" , func (t * testing.T ) {
32
- q := NewJobQueue (log .NewNopLogger (), nil )
34
+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
33
35
job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
34
36
35
37
// Start with pending job
@@ -52,7 +54,7 @@ func TestJobQueue_SyncJob(t *testing.T) {
52
54
})
53
55
54
56
t .Run ("already in-progress" , func (t * testing.T ) {
55
- q := NewJobQueue (log .NewNopLogger (), nil )
57
+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
56
58
job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
57
59
58
60
// First sync to put in in-progress
@@ -73,7 +75,7 @@ func TestJobQueue_SyncJob(t *testing.T) {
73
75
74
76
func TestJobQueue_MarkComplete (t * testing.T ) {
75
77
t .Run ("in-progress to complete" , func (t * testing.T ) {
76
- q := NewJobQueue (log .NewNopLogger (), nil )
78
+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
77
79
job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
78
80
79
81
// Start with in-progress job
@@ -103,7 +105,7 @@ func TestJobQueue_MarkComplete(t *testing.T) {
103
105
})
104
106
105
107
t .Run ("pending to complete" , func (t * testing.T ) {
106
- q := NewJobQueue (log .NewNopLogger (), nil )
108
+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
107
109
job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
108
110
109
111
// Start with pending job
@@ -130,7 +132,7 @@ func TestJobQueue_MarkComplete(t *testing.T) {
130
132
})
131
133
132
134
t .Run ("non-existent job" , func (t * testing.T ) {
133
- q := NewJobQueue (log .NewNopLogger (), nil )
135
+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
134
136
logger := & testLogger {t : t }
135
137
q .logger = logger
136
138
@@ -139,7 +141,7 @@ func TestJobQueue_MarkComplete(t *testing.T) {
139
141
})
140
142
141
143
t .Run ("already completed job" , func (t * testing.T ) {
142
- q := NewJobQueue (log .NewNopLogger (), nil )
144
+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
143
145
logger := & testLogger {t : t }
144
146
q .logger = logger
145
147
@@ -153,6 +155,111 @@ func TestJobQueue_MarkComplete(t *testing.T) {
153
155
})
154
156
}
155
157
158
+ func TestJobQueue_Enqueue (t * testing.T ) {
159
+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
160
+
161
+ job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
162
+
163
+ beforeComplete := time .Now ()
164
+ err := q .Enqueue (job , 1 )
165
+ afterComplete := time .Now ()
166
+ require .NoError (t , err )
167
+
168
+ status , ok := q .Exists (job )
169
+ require .True (t , ok , "job should exist" )
170
+ require .Equal (t , types .JobStatusPending , status )
171
+
172
+ // Verify job in pending queue
173
+ foundJob , ok := q .pending .Lookup (job .ID ())
174
+ require .True (t , ok , "job should be in pending queue" )
175
+ require .Equal (t , job , foundJob .Job )
176
+ require .Equal (t , 1 , foundJob .Priority )
177
+ require .True (t , foundJob .StartTime .IsZero ())
178
+ require .True (t , foundJob .UpdateTime .After (beforeComplete ) || foundJob .UpdateTime .Equal (beforeComplete ))
179
+ require .True (t , foundJob .UpdateTime .Before (afterComplete ) || foundJob .UpdateTime .Equal (afterComplete ))
180
+
181
+ // allow enqueueing of job with same ID if expired
182
+ job2 := types .NewJob (2 , types.Offsets {Min : 100 , Max : 200 })
183
+ q .statusMap [job2 .ID ()] = types .JobStatusExpired
184
+
185
+ err = q .Enqueue (job2 , 2 )
186
+ require .NoError (t , err )
187
+
188
+ status , ok = q .Exists (job2 )
189
+ require .True (t , ok , "job should exist" )
190
+ require .Equal (t , types .JobStatusPending , status )
191
+
192
+ // Verify job2 in pending queue
193
+ foundJob , ok = q .pending .Lookup (job2 .ID ())
194
+ require .True (t , ok , "job2 should be in pending queue" )
195
+ require .Equal (t , job2 , foundJob .Job )
196
+ require .Equal (t , 2 , foundJob .Priority )
197
+
198
+ // do not allow enqueueing of job with same ID if not expired
199
+ job3 := types .NewJob (3 , types.Offsets {Min : 120 , Max : 230 })
200
+ q .statusMap [job3 .ID ()] = types .JobStatusInProgress
201
+
202
+ err = q .Enqueue (job3 , DefaultPriority )
203
+ require .Error (t , err )
204
+ }
205
+
206
+ func TestJobQueue_RequeueExpiredJobs (t * testing.T ) {
207
+ q := NewJobQueue (JobQueueConfig {
208
+ LeaseDuration : 5 * time .Minute ,
209
+ }, log .NewNopLogger (), nil )
210
+
211
+ job1 := & JobWithMetadata {
212
+ Job : types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 }),
213
+ Priority : 1 ,
214
+ Status : types .JobStatusInProgress ,
215
+ StartTime : time .Now ().Add (- time .Hour ),
216
+ UpdateTime : time .Now ().Add (- time .Minute ),
217
+ }
218
+ // expired job
219
+ job2 := & JobWithMetadata {
220
+ Job : types .NewJob (2 , types.Offsets {Min : 300 , Max : 400 }),
221
+ Priority : 2 ,
222
+ Status : types .JobStatusInProgress ,
223
+ StartTime : time .Now ().Add (- time .Hour ),
224
+ UpdateTime : time .Now ().Add (- 6 * time .Minute ),
225
+ }
226
+
227
+ q .inProgress [job1 .ID ()] = job1
228
+ q .inProgress [job2 .ID ()] = job2
229
+ q .statusMap [job1 .ID ()] = types .JobStatusInProgress
230
+ q .statusMap [job2 .ID ()] = types .JobStatusInProgress
231
+
232
+ beforeRequeue := time .Now ()
233
+ err := q .requeueExpiredJobs ()
234
+ require .NoError (t , err )
235
+
236
+ status , ok := q .statusMap [job1 .ID ()]
237
+ require .True (t , ok )
238
+ require .Equal (t , types .JobStatusInProgress , status )
239
+
240
+ got , ok := q .inProgress [job1 .ID ()]
241
+ require .True (t , ok )
242
+ require .Equal (t , job1 , got )
243
+
244
+ status , ok = q .statusMap [job2 .ID ()]
245
+ require .True (t , ok )
246
+ require .Equal (t , types .JobStatusPending , status )
247
+
248
+ got , ok = q .pending .Lookup (job2 .ID ())
249
+ require .True (t , ok )
250
+ require .Equal (t , job2 .Job , got .Job )
251
+ require .Equal (t , types .JobStatusPending , got .Status )
252
+ require .Equal (t , job2 .Priority , got .Priority )
253
+ require .True (t , got .StartTime .IsZero ())
254
+ require .True (t , got .UpdateTime .After (beforeRequeue ) || got .UpdateTime .Equal (beforeRequeue ))
255
+
256
+ require .Equal (t , 1 , q .completed .Len ())
257
+ got , ok = q .completed .Pop ()
258
+ require .True (t , ok )
259
+ job2 .Status = types .JobStatusExpired
260
+ require .Equal (t , job2 , got )
261
+ }
262
+
156
263
// testLogger implements log.Logger for testing
157
264
type testLogger struct {
158
265
t * testing.T
0 commit comments