@@ -625,7 +625,64 @@ class StreamBatchedPipelineABC(BatchedPipelineABC):
625625 def __init__ (self ):
626626 super ().__init__ ()
627627
628- def _compiled_forward (self , resume_step : int = 0 , batch_size : int | None = None , resume_from_last : bool = True ):
628+ def _compiled_forward (self , resume_step : int = 0 , batch_size : int | None = None , resume_from_last : bool = True , transactional_resume : bool = False ):
629+ if transactional_resume :
630+ if not resume_from_last or resume_step != 0 :
631+ raise ValueError ("Transactional streaming requires resume_from_last=True and resume_step=0" )
632+ return self ._transactional_forward (batch_size )
633+ return self ._legacy_stream_forward (resume_step , batch_size , resume_from_last )
634+
635+ def _transactional_forward (self , batch_size ):
636+ from dataflow .utils .stream_transaction import StreamTransactionCoordinator
637+ from dataflow .utils .stream_transaction import TransactionError
638+
639+ if not self .compiled :
640+ raise RuntimeError ("Pipeline is not compiled yet" )
641+ nodes = [node for node in self .op_nodes_list if node .op_obj is not None ]
642+ with StreamTransactionCoordinator (nodes , batch_size ) as coordinator :
643+ while coordinator .manifest ["stage" ] < len (nodes ):
644+ stage = coordinator .manifest ["stage" ]
645+ node = nodes [stage ]
646+ storage = node .storage
647+ storage .batch_size = batch_size
648+ batch = coordinator .manifest ["batch" ]
649+ count = coordinator .input_rows (stage )
650+ total_batches = (count + batch_size - 1 ) // batch_size
651+ if batch > total_batches :
652+ raise TransactionError ("Committed cursor exceeds stage input" )
653+ if batch == total_batches :
654+ coordinator .transition (stage )
655+ continue
656+ storage .batch_step = batch
657+ stream = storage .iter_chunks ()
658+ try :
659+ for _ in range (batch ):
660+ if next (stream , None ) is None :
661+ raise TransactionError ("Input stream shorter than committed cursor" )
662+ chunk = next (stream , None )
663+ finally :
664+ if "chunk" not in locals () and hasattr (stream , "close" ):
665+ stream .close ()
666+ if chunk is None :
667+ raise TransactionError ("Input stream shorter than manifest row count" )
668+ storage ._current_streaming_chunk = chunk
669+ coordinator .begin (stage , batch )
670+ try :
671+ node .op_obj .run (storage = storage , ** node .kwargs )
672+ coordinator .commit (stage , batch )
673+ except BaseException :
674+ coordinator .abort ()
675+ raise
676+ finally :
677+ storage ._current_streaming_chunk = None
678+ if hasattr (stream , "close" ):
679+ stream .close ()
680+ if "chunk" in locals ():
681+ del chunk
682+ storage .batch_step = coordinator .manifest ["batch" ]
683+ return None
684+
685+ def _legacy_stream_forward (self , resume_step : int = 0 , batch_size : int | None = None , resume_from_last : bool = True ):
629686 """
630687 resume_step (int): resume inference from this step
631688 batch_size (int|None): if set, run the pipeline in batch mode with this batch size
0 commit comments