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]
