@@ -112,6 +112,9 @@ private ComfyCliResult runProcess(String stdin, long timeoutMs, String... args)
112112 timedOut = true ;
113113 terminate (process );
114114 } finally {
115+ // Closing our stdin pipe first guarantees a writer cannot extend
116+ // the call lifetime if the child/descendant stopped consuming it.
117+ closeQuietly (process .getOutputStream ());
115118 join (stdinWriter , config .getStreamDrainTimeoutMillis ());
116119 drainReaders (process , stdoutReader , stderrReader );
117120 }
@@ -148,18 +151,20 @@ private void terminate(Process process) {
148151
149152 private void drainReaders (Process process , Thread stdoutReader , Thread stderrReader ) {
150153 long drainMs = config .getStreamDrainTimeoutMillis ();
151- join (stdoutReader , drainMs );
152- join (stderrReader , drainMs );
154+ long deadlineNanos = System .nanoTime () + TimeUnit .MILLISECONDS .toNanos (drainMs );
155+ joinUntil (stdoutReader , deadlineNanos );
156+ joinUntil (stderrReader , deadlineNanos );
153157 if (stdoutReader .isAlive () || stderrReader .isAlive ()) {
154158 // A descendant may still own inherited pipe write-ends. Closing
155159 // our read-ends prevents that descendant from extending the Java
156160 // call lifetime or retaining reader threads.
157161 closeQuietly (process .getInputStream ());
158162 closeQuietly (process .getErrorStream ());
159- join (stdoutReader , Math .min (250L , drainMs ));
160- join (stderrReader , Math .min (250L , drainMs ));
163+ long closeDeadline = System .nanoTime ()
164+ + TimeUnit .MILLISECONDS .toNanos (Math .min (250L , drainMs ));
165+ joinUntil (stdoutReader , closeDeadline );
166+ joinUntil (stderrReader , closeDeadline );
161167 }
162- closeQuietly (process .getOutputStream ());
163168 }
164169
165170 private static void copy (InputStream input , OutputStream output ) {
@@ -204,6 +209,15 @@ private static void join(Thread thread, long millis) {
204209 }
205210 }
206211
212+ private static void joinUntil (Thread thread , long deadlineNanos ) {
213+ if (thread == null || thread == Thread .currentThread () || !thread .isAlive ()) return ;
214+ long remainingNanos = deadlineNanos - System .nanoTime ();
215+ if (remainingNanos <= 0 ) return ;
216+ long millis = TimeUnit .NANOSECONDS .toMillis (remainingNanos );
217+ if (millis <= 0 ) millis = 1 ;
218+ join (thread , millis );
219+ }
220+
207221 private static void closeQuietly (java .io .Closeable closeable ) {
208222 if (closeable == null ) return ;
209223 try {
0 commit comments