mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 08:24:13 +00:00
Prior to this commit, only the very first AsynchronousFileChannel#write call in DataBufferUtils$WriteCompletionHandler#hookOnNext(DataBuffer) was guarded against exceptions escaping synchronously, and even then only via `catch (RuntimeException ex)`, per the original fix for gh-36184. While widening that guard to match the read side's `catch (Throwable ex)` combined with `Exceptions.throwIfFatal(ex)` (see gh-37143), we discovered that completed(Integer, Attachment) contains two more direct `this.channel.write(...)` calls -- for continuing a partial write and for advancing to the next ByteBuffer within the same DataBuffer's iterator -- neither of which was guarded at all. Since completed() is invoked by the channel's own completion callback, typically on a different thread than the one that issued the original write, a synchronous exception escaping either of those calls has no path back to the FluxSink, and the resulting Flux hangs indefinitely, exactly as described in gh-37143, for any write that receives a partial OS write or spans multiple ByteBuffers. To address that, this commit extracts a private write(ByteBuffer, long, Attachment) helper that wraps the channel.write(...) call with a try/catch block, routing any non-fatal Throwable -- via Exceptions.throwIfFatal() -- to the existing failed(Throwable, Attachment) handler. All three call sites (hookOnNext() and both branches in completed()) now go through this helper, ensuring the Flux always terminates with a proper error signal instead of hanging silently, regardless of which write attempt fails or which thread it fails on. See gh-36184 See gh-37143 Closes gh-37145