@@ -246,6 +246,12 @@ async def subscribe(self) -> AsyncGenerator[EngineEventBatch, None]:
246246 )
247247 if generation != self ._generation :
248248 continue
249+ if replay_batches is not None :
250+ # The gap is resolved up to the live message: every
251+ # missing batch still buffered was forwarded and the
252+ # rest is permanently lost. Advance now so a live
253+ # decode failure below cannot replay the same range.
254+ self ._last_seq = seq - 1
249255 if replay_batches :
250256 replay_telemetry .mark ("replay_fetch" )
251257 yield EngineEventBatch (
@@ -454,7 +460,17 @@ async def _replay_missing_batches(
454460 return None
455461 if generation != self ._generation :
456462 return None
457- if len (frames ) != 3 :
463+ if len (frames ) == 4 :
464+ # vLLM PR #45177 added topic to replay replies. ROUTER
465+ # consumes client_id, so DEALER receives
466+ # (delimiter, topic, seq_bytes, payload).
467+ _ , _ , replay_seq_bytes , replay_payload = frames
468+ elif len (frames ) == 3 :
469+ # Before vLLM PR #45177, replay replies had no topic and
470+ # DEALER received (delimiter, seq_bytes, payload).
471+ _ , replay_seq_bytes , replay_payload = frames
472+ else :
473+ self ._replace_replay_socket (dealer , generation )
458474 logger .warning (
459475 "dropping malformed kv event replay frames" ,
460476 step = "zmq_replay" ,
@@ -466,7 +482,7 @@ async def _replay_missing_batches(
466482 },
467483 )
468484 return None
469- if frames [ 1 ] == _END_SEQ :
485+ if replay_seq_bytes == _END_SEQ :
470486 if logger .is_debug_enabled ():
471487 logger .debug (
472488 "completed vLLM ZMQ replay" ,
@@ -479,9 +495,15 @@ async def _replay_missing_batches(
479495 },
480496 )
481497 return replay_batches
482- replay_seq = int .from_bytes (frames [1 ], "big" )
498+ replay_seq = int .from_bytes (replay_seq_bytes , "big" )
499+ # The replay endpoint returns every buffered batch with
500+ # seq >= gap_start_seq, including the live batch that exposed the
501+ # gap and anything newer; those arrive (or arrived) live, so only
502+ # the missing range is forwarded here. Keep draining to END.
503+ if replay_seq < gap_start_seq or replay_seq >= current_seq :
504+ continue
483505 batch = self ._msgpack_helper .decode (
484- frames [ 2 ] ,
506+ replay_payload ,
485507 step = "zmq_replay" ,
486508 tags = {
487509 "gap_start_seq" : gap_start_seq ,
@@ -490,6 +512,7 @@ async def _replay_missing_batches(
490512 },
491513 )
492514 if batch is None :
515+ self ._replace_replay_socket (dealer , generation )
493516 return None
494517 if logger .is_debug_enabled ():
495518 logger .debug (
0 commit comments