@@ -66,7 +66,6 @@ def __init__( # noqa: PLR0913
6666 # Coordination
6767 self .workers_started : bool = False
6868 self .source_exhausted : bool = False
69- self .workers_done : bool = False
7069 self .last_send_time : float = time .time ()
7170
7271 # Tasks
@@ -195,9 +194,7 @@ async def _process_item(self, item: T) -> ClassificationInput:
195194
196195 async def _collect_processed_items (self ) -> None :
197196 """Collect processed items from workers."""
198- active_workers = self .num_workers
199-
200- while active_workers > 0 or not self .output_queue .empty ():
197+ while not self ._all_workers_done () or not self .output_queue .empty ():
201198 try :
202199 # Wait for processed item with timeout
203200 processed_item = await asyncio .wait_for (
@@ -209,7 +206,7 @@ async def _collect_processed_items(self) -> None:
209206
210207 except asyncio .TimeoutError : # noqa: PERF203 Exception used in control flow to detect empty queue
211208 # No items available, continue waiting
212- if self .source_exhausted and self .output_queue .empty ():
209+ if self ._all_workers_done () and self .output_queue .empty ():
213210 break
214211 except asyncio .CancelledError :
215212 # If cancelled, always continue collecting to keep workers
@@ -221,7 +218,6 @@ async def _collect_processed_items(self) -> None:
221218 # Never break - always continue to keep the stream alive
222219 continue
223220
224- self .workers_done = True
225221 self .logger .debug ("All workers finished processing" )
226222
227223 async def _get_next_batch (self ) -> ClassifyRequest :
@@ -235,7 +231,7 @@ async def _get_next_batch(self) -> ClassifyRequest:
235231 # Wait for batch to fill up or timeout
236232 while (
237233 len (self .processed_items ) < self .max_batch_size
238- and not self .workers_done
234+ and not self ._all_workers_done ()
239235 ):
240236 try :
241237 await asyncio .wait_for (
@@ -263,7 +259,7 @@ async def _get_next_batch(self) -> ClassifyRequest:
263259
264260 # Keep stream alive with keepalives to continue receiving shared queue
265261 # results
266- if self .workers_done :
262+ if self ._all_workers_done () :
267263 self .logger .debug (
268264 "All work complete, sending keepalive to continue "
269265 "receiving shared queue results"
@@ -279,11 +275,17 @@ async def _get_next_batch(self) -> ClassifyRequest:
279275 await asyncio .sleep (0.1 )
280276 return self ._create_keepalive_request (time .time ())
281277
278+ def _all_workers_done (self ) -> bool :
279+ """Check if all worker tasks are done."""
280+ if not self .worker_tasks :
281+ return True
282+ return all (task .done () for task in self .worker_tasks )
283+
282284 async def _wait_for_items (self ) -> None :
283285 """Wait for items to become available."""
284286 while (
285287 len (self .processed_items ) < self .max_batch_size
286- and not self .workers_done
288+ and not self ._all_workers_done ()
287289 ):
288290 try :
289291 await asyncio .sleep (0.01 ) # Small delay to prevent busy waiting
0 commit comments