ARV0007 opened a new pull request, #23926:
URL: https://github.com/apache/kafka/pull/23926

   `KafkaProducer.close(timeout)` can block forever. After the timed join, 
`close()` force closes the sender and then joins the I/O thread with no 
timeout. If a user callback is blocking that thread, for example while the 
forced close fails the pending records, `close()` waits for as long as the 
callback does, so the timeout is not honoured. `close(Duration.ZERO)` hangs the 
same way.
   
   Separately, `Timer.remainingMs()` can return 0 and `Thread.join(0)` waits 
forever, so the first, timed join is unbounded too when the close timer has 
already run out.
   
   This change:
   - caps the wait for the I/O thread after a forced close at `max.block.ms`, 
and logs a warning if the thread is still alive afterwards
   - never calls `Thread.join(0)`
   - documents the bound in the `close(Duration)` Javadoc
   
   The forced shutdown normally takes milliseconds, so normal behaviour is 
unchanged: `close()` still waits for it, and the failed records' callbacks 
still run before `close()` returns. Only a blocked I/O thread now leads to a 
bounded wait instead of a hang. The new logic sits in two small helpers so that 
`close()` keeps its current structure.
   
   An alternative is to bound the wait by the time left on the close timer, as 
the JIRA suggests. That keeps `close()` within its timeout, but whenever the 
timeout expires, callbacks and interceptors of the failed records would run 
after `close()` returns, while it closes the interceptors and metrics. Happy to 
switch if reviewers prefer that, or a different cap.
   
   Testing:
   - `testCloseWithTimeoutReturnsWhileCallbackIsBlocked` and 
`testCloseWithZeroTimeoutReturnsWhileCallbackIsBlocked`: a send callback blocks 
during the forced close, and `close(100 ms)` / `close(0)` must return. Both 
fail on trunk (`close()` is still blocked after 10 s) and pass with this change.
   - `testForcedCloseStillRunsCallbacksBeforeReturning`: guards the unchanged 
behaviour, and passes before and after.
   - All tests in `org.apache.kafka.clients.producer` pass locally (615 passed, 
3 skipped; macOS, JDK 26), as do Checkstyle and SpotBugs for `clients`.
   
   This complements #23857 (KAFKA-21132), which bounds the transactional abort 
during close.
   
   Co-Authored-By: Claude Opus 5.5 <[email protected]>


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to