Skip to content

ZOOKEEPER-5021: Exit from zkCli when interrupt (Ctrl-C) or EOF (Ctrl-D) is pressed#2357

Closed
PDavid wants to merge 1 commit intoapache:masterfrom
PDavid:ZOOKEEPER-5021-cli-fix-eof-interrupt
Closed

ZOOKEEPER-5021: Exit from zkCli when interrupt (Ctrl-C) or EOF (Ctrl-D) is pressed#2357
PDavid wants to merge 1 commit intoapache:masterfrom
PDavid:ZOOKEEPER-5021-cli-fix-eof-interrupt

Conversation

@PDavid
Copy link
Copy Markdown
Contributor

@PDavid PDavid commented Mar 6, 2026

Problem

Closing the input stream for a terminal by pressing "Ctrl-D" should automatically exit the interactive shell, but the bin/zkCli.sh does not exit, but does disable JLine support, leaving you at a prompt-less terminal. Pressing "Ctrl-D" a second time exited correctly, and so did entering "quit" (without JLine support enabled).

Cause

After the JLine 3.x upgrade, pressing Ctrl-C or Ctrl-D results in InvocationTargetException which we caught and set the jlinemissing flag to true to fall back to the promptless shell.

Fix

When the cause of the InvocationTargetException is either EndOfFileException or UserInterruptException, we should not set the jlinemissing flag to true to not fall back to the promptless shell.
This way the behavior aligns with what we had before the JLine 3.x upgrade.

…D) is pressed

Problem

Closing the input stream for a terminal by pressing "Ctrl-D" should
automatically exit the interactive shell, but the bin/zkCli.sh does
not exit, but does disable JLine support, leaving you at a prompt-less
terminal. Pressing "Ctrl-D" a second time exited correctly, and so did
entering "quit" (without JLine support enabled).

Cause

After the JLine 3.x upgrade, pressing Ctrl-C or Ctrl-D results in InvocationTargetException which we caught and set the jlinemissing flag to true to fall back to the promptless shell.

Fix

When the cause of the InvocationTargetException is either EndOfFileException or UserInterruptException, we should not set the jlinemissing flag to true to not fall back to the promptless shell.
@PDavid
Copy link
Copy Markdown
Contributor Author

PDavid commented Mar 6, 2026

Testing

Built the project with mvn clean install -DskipTests
Set up config: cp conf/zoo_sample.cfg conf/zoo.cfg
Started ZooKeeper server: bin/zkServer.sh start
Started the ZK CLI: bin/zkCli.sh -server 127.0.0.1:2181

After this fix pressing a Ctrl-D (or Ctrl-C) one time should exit the ZK shell (and should not print "JLine support is disabled" and drop you into prompltess shell where you have to Ctrl-D / Ctrl-C again).

...
2026-03-06 15:03:03,062 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:java.library.path=/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib
2026-03-06 15:03:03,062 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:java.io.tmpdir=/tmp
2026-03-06 15:03:03,062 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:java.compiler=<NA>
2026-03-06 15:03:03,062 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:os.name=Linux
2026-03-06 15:03:03,062 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:os.arch=amd64
2026-03-06 15:03:03,062 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:os.version=6.17.0-14-generic
2026-03-06 15:03:03,062 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:user.name=david
2026-03-06 15:03:03,062 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:user.home=/home/david
2026-03-06 15:03:03,063 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:user.dir=/home/david/projects/upstream/zookeeper
2026-03-06 15:03:03,063 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:jvm.memory.free=232MB
2026-03-06 15:03:03,063 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:jvm.memory.max=256MB
2026-03-06 15:03:03,063 [myid:] - INFO  [main:o.a.z.Environment@98] - Client environment:jvm.memory.total=256MB
2026-03-06 15:03:03,064 [myid:] - INFO  [main:o.a.z.ZooKeeper@1123] - Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@f8c1ddd
2026-03-06 15:03:03,068 [myid:] - INFO  [main:o.a.z.c.X509Util@85] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
2026-03-06 15:03:03,173 [myid:] - INFO  [main:o.a.z.c.X509Util@109] - Default TLS protocol is TLSv1.3, supported TLS protocols are [TLSv1.3, TLSv1.2, TLSv1.1, TLSv1, SSLv3, SSLv2Hello]
2026-03-06 15:03:03,175 [myid:] - INFO  [main:o.a.z.c.HostConnectionManager@127] - HostConnectionManager initialized with 1 servers
2026-03-06 15:03:03,178 [myid:] - INFO  [main:o.a.z.ClientCnxnSocket@235] - jute.maxbuffer value is 1048575 Bytes
2026-03-06 15:03:03,181 [myid:] - INFO  [main:o.a.z.ClientCnxn@1723] - zookeeper.request.timeout value is 0. feature enabled=false
Welcome to ZooKeeper!
JLine support is enabled
2026-03-06 15:03:03,185 [myid:127.0.0.1:2181] - INFO  [main-SendThread(127.0.0.1:2181):o.a.z.ClientCnxn$SendThread@1154] - Opening socket connection to server /127.0.0.1:2181.
2026-03-06 15:03:03,185 [myid:127.0.0.1:2181] - INFO  [main-SendThread(127.0.0.1:2181):o.a.z.ClientCnxn$SendThread@1156] - SASL config status: Will not attempt to authenticate using SASL (unknown error)
2026-03-06 15:03:03,191 [myid:127.0.0.1:2181] - INFO  [main-SendThread(127.0.0.1:2181):o.a.z.ClientCnxn$SendThread@1007] - Socket connection established, initiating session, client: /127.0.0.1:38016, server: /127.0.0.1:2181
2026-03-06 15:03:03,195 [myid:127.0.0.1:2181] - INFO  [main-SendThread(127.0.0.1:2181):o.a.z.ClientCnxn$SendThread@1427] - Session establishment complete on server /127.0.0.1:2181, session id = 0x100139a92070023, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null zxid: -1
[zk: 127.0.0.1:2181(CONNECTED) 0] 
2026-03-06 15:03:06,302 [myid:] - INFO  [main:o.a.z.u.ServiceUtils@45] - Exiting JVM with code 0
$

Copy link
Copy Markdown
Contributor

@anmolnar anmolnar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm.

@PDavid
Copy link
Copy Markdown
Contributor Author

PDavid commented Mar 24, 2026

Many thanks for your reviews. 👍 Are you happy merging this fix or is it better to wait for more reviews on this?

endOfFileExceptionC = Class.forName("org.jline.reader.EndOfFileException");
userInterruptExceptionC = Class.forName("org.jline.reader.UserInterruptException");

System.out.println("JLine support is enabled");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about setting jlinemissing to true initially and to false here ?

Copy link
Copy Markdown
Contributor Author

@PDavid PDavid Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, many thanks! 👍
This makes perfect sense and this is so much simpler and easier than I implemented here. 🤦‍♂️ 😄

I tried this out and works nicely. Please check it here: #2369

@PDavid
Copy link
Copy Markdown
Contributor Author

PDavid commented Mar 31, 2026

Closing this in favor of #2369

@PDavid PDavid closed this Mar 31, 2026
@ctubbsii
Copy link
Copy Markdown
Member

Closing this in favor of #2369

For what it's worth, you don't need to create a new PR if changing the implementation in response to code review feedback. You can just push to the branch you made the PR from, and it automatically updates the PR with the changes.

@PDavid
Copy link
Copy Markdown
Contributor Author

PDavid commented Apr 1, 2026

Closing this in favor of #2369

For what it's worth, you don't need to create a new PR if changing the implementation in response to code review feedback. You can just push to the branch you made the PR from, and it automatically updates the PR with the changes.

Thanks, true, I know. 👍
Just wanted to raise the another PR because that solution is quite different and to have both solutions available and you all can choose which do you think fits better. But changing the flag is simpler I think.

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.

4 participants