@@ -10,9 +10,11 @@ import (
1010 "github.com/grafana/loki/v3/pkg/blockbuilder/types"
1111)
1212
13+ var testQueueCfg = JobQueueConfig {}
14+
1315func TestJobQueue_SyncJob (t * testing.T ) {
1416 t .Run ("non-existent to in-progress" , func (t * testing.T ) {
15- q := NewJobQueue (log .NewNopLogger (), nil )
17+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
1618 job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
1719 jobID := job .ID ()
1820
@@ -29,7 +31,7 @@ func TestJobQueue_SyncJob(t *testing.T) {
2931 })
3032
3133 t .Run ("pending to in-progress" , func (t * testing.T ) {
32- q := NewJobQueue (log .NewNopLogger (), nil )
34+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
3335 job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
3436
3537 // Start with pending job
@@ -52,7 +54,7 @@ func TestJobQueue_SyncJob(t *testing.T) {
5254 })
5355
5456 t .Run ("already in-progress" , func (t * testing.T ) {
55- q := NewJobQueue (log .NewNopLogger (), nil )
57+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
5658 job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
5759
5860 // First sync to put in in-progress
@@ -73,7 +75,7 @@ func TestJobQueue_SyncJob(t *testing.T) {
7375
7476func TestJobQueue_MarkComplete (t * testing.T ) {
7577 t .Run ("in-progress to complete" , func (t * testing.T ) {
76- q := NewJobQueue (log .NewNopLogger (), nil )
78+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
7779 job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
7880
7981 // Start with in-progress job
@@ -103,7 +105,7 @@ func TestJobQueue_MarkComplete(t *testing.T) {
103105 })
104106
105107 t .Run ("pending to complete" , func (t * testing.T ) {
106- q := NewJobQueue (log .NewNopLogger (), nil )
108+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
107109 job := types .NewJob (1 , types.Offsets {Min : 100 , Max : 200 })
108110
109111 // Start with pending job
@@ -130,7 +132,7 @@ func TestJobQueue_MarkComplete(t *testing.T) {
130132 })
131133
132134 t .Run ("non-existent job" , func (t * testing.T ) {
133- q := NewJobQueue (log .NewNopLogger (), nil )
135+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
134136 logger := & testLogger {t : t }
135137 q .logger = logger
136138
@@ -139,7 +141,7 @@ func TestJobQueue_MarkComplete(t *testing.T) {
139141 })
140142
141143 t .Run ("already completed job" , func (t * testing.T ) {
142- q := NewJobQueue (log .NewNopLogger (), nil )
144+ q := NewJobQueue (testQueueCfg , log .NewNopLogger (), nil )
143145 logger := & testLogger {t : t }
144146 q .logger = logger
145147
@@ -153,6 +155,111 @@ func TestJobQueue_MarkComplete(t *testing.T) {
153155 })
154156}
155157
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+
156263// testLogger implements log.Logger for testing
157264type testLogger struct {
158265 t * testing.T
0 commit comments