@@ -291,6 +291,40 @@ func waitForCondition(t *testing.T, signalCh <-chan queueMySQL.HookSignal, condi
291291 }
292292}
293293
294+ // waitForLag waits for subscriber polls until the selected consumer lag
295+ // converges to expected. Lag must not advance past the expected value.
296+ func waitForLag (
297+ t * testing.T ,
298+ ctx context.Context ,
299+ admin * queueAdmin.AdminStore ,
300+ signalCh <- chan queueMySQL.HookSignal ,
301+ topic string ,
302+ consumerGroup string ,
303+ partitionKey string ,
304+ expected int64 ,
305+ ) int64 {
306+ t .Helper ()
307+
308+ for {
309+ lags , err := admin .ConsumerLag (ctx , topic )
310+ require .NoError (t , err )
311+
312+ var actual int64 = - 1
313+ for _ , lag := range lags {
314+ if lag .ConsumerGroup == consumerGroup && lag .PartitionKey == partitionKey {
315+ actual = lag .Lag
316+ break
317+ }
318+ }
319+
320+ require .GreaterOrEqual (t , actual , expected , "watermark advanced past expected lag" )
321+ if actual == expected {
322+ return actual
323+ }
324+ waitForSignal (t , signalCh , queueMySQL .SignalDeliveryCheck )
325+ }
326+ }
327+
294328func (s * SQLQueueIntegrationSuite ) TestPublishAndSubscribe () {
295329 t := s .T ()
296330
@@ -2396,18 +2430,9 @@ func (s *SQLQueueIntegrationSuite) TestWatermarkAdvancesContiguously() {
23962430
23972431 admin := queueAdmin .NewAdminStore (s .db )
23982432
2399- // Helper to get consumer lag
2400- getLag := func () int64 {
2401- lags , err := admin .ConsumerLag (s .ctx , topic )
2402- require .NoError (t , err )
2403- for _ , lag := range lags {
2404- if lag .ConsumerGroup == "watermark-cg" && lag .PartitionKey == "wm-part" {
2405- return lag .Lag
2406- }
2407- }
2408- return - 1
2409- }
2410-
2433+ // Watermark advancement is incremental and runs in the subscriber poll loop.
2434+ // A delivery-check signal proves one poll completed, but the watermark may
2435+ // need another poll to converge after several acknowledgements.
24112436 // Ack message 3 first (out of order)
24122437 require .NoError (t , deliveries ["wm-msg-3" ].Ack (s .ctx ))
24132438 t .Logf ("Acked msg-3" )
@@ -2417,31 +2442,24 @@ func (s *SQLQueueIntegrationSuite) TestWatermarkAdvancesContiguously() {
24172442 require .NoError (t , deliveries ["wm-msg-2" ].Ack (s .ctx ))
24182443 t .Logf ("Acked msg-1 and msg-2" )
24192444
2420- // Wait for poll loop to advance watermark
2421- waitForSignal (t , signalCh , queueMySQL .SignalDeliveryCheck )
2422-
24232445 // After acking 1,2,3: watermark should advance to 3, lag should be 2 (msg-4, msg-5)
2424- lag := getLag ( )
2446+ lag := waitForLag ( t , s . ctx , admin , signalCh , topic , "watermark-cg" , "wm-part" , 2 )
24252447 assert .Equal (t , int64 (2 ), lag , "lag should be 2 after acking 1,2,3 (4 and 5 remain)" )
24262448 t .Logf ("After acking 1,2,3: lag=%d" , lag )
24272449
24282450 // Ack message 5 (skip 4) — watermark should NOT advance past 3
24292451 require .NoError (t , deliveries ["wm-msg-5" ].Ack (s .ctx ))
24302452 t .Logf ("Acked msg-5 (skipping msg-4)" )
24312453
2432- waitForSignal (t , signalCh , queueMySQL .SignalDeliveryCheck )
2433-
2434- lag = getLag ()
2454+ lag = waitForLag (t , s .ctx , admin , signalCh , topic , "watermark-cg" , "wm-part" , 2 )
24352455 assert .Equal (t , int64 (2 ), lag , "lag should still be 2 after acking 5 but not 4" )
24362456 t .Logf ("After acking 5 (not 4): lag=%d" , lag )
24372457
24382458 // Ack message 4 — now all 5 are contiguous, watermark should advance to 5
24392459 require .NoError (t , deliveries ["wm-msg-4" ].Ack (s .ctx ))
24402460 t .Logf ("Acked msg-4" )
24412461
2442- waitForSignal (t , signalCh , queueMySQL .SignalDeliveryCheck )
2443-
2444- lag = getLag ()
2462+ lag = waitForLag (t , s .ctx , admin , signalCh , topic , "watermark-cg" , "wm-part" , 0 )
24452463 assert .Equal (t , int64 (0 ), lag , "lag should be 0 after acking all 5 messages" )
24462464 t .Logf ("After acking all 5: lag=%d" , lag )
24472465
0 commit comments