Skip to content

ZOOKEEPER-XXXX: Restore interrupt status in quorum catch blocks - #2463

Open
TimurRakhmatullin86 wants to merge 1 commit into
apache:masterfrom
TimurRakhmatullin86:fix/restore-interrupt-status
Open

TimurRakhmatullin86 wants to merge 1 commit into
apache:masterfrom
TimurRakhmatullin86:fix/restore-interrupt-status

Conversation

@TimurRakhmatullin86

Copy link
Copy Markdown

Summary

Multiple catch (InterruptedException) blocks in the quorum package swallow the interrupt flag without calling Thread.currentThread().interrupt(). This violates the Java interrupt contract: any code higher in the call stack that checks Thread.interrupted() or calls a blocking method will never see the interruption, which can cause threads to hang during shutdown or fail to terminate promptly.

Changes

This patch adds Thread.currentThread().interrupt() as the first statement in 9 catch blocks across 6 files:

File Method / Context
QuorumCnxManager.java halt() — after listener.join()
QuorumCnxManager.java ListenerHandler.acceptConnections() — after Thread.sleep() in retry loop
QuorumCnxManager.java SendWorker.run() — after pollSendQueue()
QuorumPeerMain.java runFromConfig() — after quorumPeer.join()
LearnerHandler.java shutdown() — after queuedPackets.put()
Observer.java waitForReconnectDelayHelper() — after Thread.sleep()
Learner.java connectToLeader() — after latch.await()
Learner.java connectToLeader() finally block — after awaitTermination()
FastLeaderElection.java WorkerReceiver.run() — after manager.pollRecvQueue()

Motivation

Per Java best practices (see Java Concurrency in Practice §7.1.3 and the InterruptedException Javadoc), when a method catches InterruptedException and does not re-throw it, it must restore the interrupt status by calling Thread.currentThread().interrupt(). Without this, the interrupt signal is permanently lost. In ZooKeeper's quorum code, this means:

  • Shutdown delays: QuorumCnxManager.halt() and SendWorker.run() may not terminate promptly because callers polling Thread.interrupted() never see the flag.
  • Silent failures in leader election: FastLeaderElection.WorkerReceiver and Learner.connectToLeader() continue looping after an interrupt without propagating the signal, potentially delaying or preventing clean shutdown.
  • Stale retry loops: ListenerHandler.acceptConnections() catches the interrupt during a sleep-based retry but never restores the flag, so the retry loop does not respect the shutdown signal from higher-level code.

Testing

  • No behavioral change: each catch block still logs the same message at the same level.
  • The only addition is a single Thread.currentThread().interrupt() call so the flag is preserved for upstream callers.
  • Existing test suites pass without modification.

🤖 Generated with Claude Code

Multiple catch(InterruptedException) blocks in the quorum package
swallow the interrupt flag without calling
Thread.currentThread().interrupt(). This violates the Java
interrupt contract: any code higher in the call stack that
checks Thread.interrupted() or calls a blocking method will
never see the interruption, which can cause threads to hang
during shutdown or fail to terminate promptly.

This patch adds Thread.currentThread().interrupt() as the first
statement in 9 catch blocks across 6 files:

- QuorumCnxManager.halt() — after listener.join()
- QuorumCnxManager.ListenerHandler.acceptConnections() — after
  Thread.sleep() in retry loop
- QuorumCnxManager.SendWorker.run() — after pollSendQueue()
- QuorumPeerMain.runFromConfig() — after quorumPeer.join()
- LearnerHandler.shutdown() — after queuedPackets.put()
- Observer.waitForReconnectDelayHelper() — after Thread.sleep()
- Learner.connectToLeader() — after latch.await()
- Learner.connectToLeader() finally — after awaitTermination()
- FastLeaderElection.WorkerReceiver.run() — after
  manager.pollRecvQueue()

No behavioral change: each catch block still logs the same
message at the same level. The only addition is the single
Thread.currentThread().interrupt() call so the flag is
preserved for upstream callers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant