@@ -438,16 +438,29 @@ async def _run_command_ssh(
438
438
stderr_lines : list [str ] = []
439
439
440
440
async def _read_stream (stream , dest : list [str ], log_type : str ) -> None :
441
+ buf = ""
441
442
while True :
442
- line = await stream .readline ( )
443
- if not line :
443
+ chunk = await stream .read ( 32768 )
444
+ if not chunk :
444
445
break
445
- if isinstance (line , (bytes , bytearray )):
446
- line = line .decode (errors = "ignore" )
447
- line = line .rstrip ("\n " )
448
- dest .append (line )
446
+ if isinstance (chunk , (bytes , bytearray )):
447
+ chunk = chunk .decode (errors = "ignore" )
448
+ buf += chunk
449
+
450
+ # Emit complete lines; keep last partial in buf
451
+ * lines , buf = buf .split ("\n " )
452
+ for ln in lines :
453
+ ln = ln .rstrip ("\r " )
454
+ dest .append (ln ) # <<< store it
455
+ if log_output :
456
+ await log (db , redis , frame .id , log_type , ln )
457
+
458
+ # Flush any leftover partial line at EOF
459
+ if buf :
460
+ ln = buf .rstrip ("\r " )
461
+ dest .append (ln ) # <<< store the final partial
449
462
if log_output :
450
- await log (db , redis , frame .id , log_type , line )
463
+ await log (db , redis , frame .id , log_type , ln )
451
464
452
465
stdout_task = asyncio .create_task (_read_stream (proc .stdout , stdout_lines , "stdout" ))
453
466
stderr_task = asyncio .create_task (_read_stream (proc .stderr , stderr_lines , "stderr" ))
0 commit comments