redis-cli: Accept commands in subscribed mode#11873
redis-cli: Accept commands in subscribed mode#11873oranagra merged 13 commits intoredis:unstablefrom
Conversation
The message "Reading messages... (press Ctrl-C to quit)" is replaced by "Reading messages... (press Ctrl-C to quit or enter to type command)". When enter is pressed, a prompt for entering commands appear. After entering one command and the reply is displayed, you get the "Reading messages..." again. This is added to the repl loop in redis-cli and in the corresponding place for non-interactive mode. This allows users to subscribe to more channels, to try out UNSUBSCRIBE and to combine pubsub with other features such as push messages from client tracking. An indication "(subscribed mode)" is included in the prompt when entering commands in subscribed mode. Also: * Fix problem that UNSUBSCRIBE hanged when used with RESP3 and push callback, without first entering subscribe mode. It hanged because UNSUBSCRIBE gets one or more push replies but no in-band reply. * Fix problem that UNSUBSCRIBE with 2+ channels with RESP2 without first entering subscribed mode caused the request-response pairs to get out of sync. The responses for UNSUBSCRIBE ch1 ch2; PING results appeared as one unsubscribe message for ch1 as a response to UNSUBSCRIBE and the unsubscribe message for ch2 as a response to PING. (Pong appeared when the next command after that is entered.) * Exit subscribed mode after RESET. * Set the config.resp3 variable after HELLO, based on its reply.
725c9af to
df7409c
Compare
|
Very nice! |
|
@bjosv You can only type commands at the prompt. You need to press enter first to make the prompt appear. Linenoise (the readline clone) consumes all pending input. That's why. |
|
@bjosv I changed "press enter" to "press any key" to avoid the confusion you experienced. I hope it's more intuitive now. Added tests for TTY and non-TTY. |
|
@bjosv The color 90 "bright black (gray)" is the same color as already used for command hints. I guess you don't see hints either then? |
|
Nope, seems that I'm missing out of some good stuff 😳 |
|
wow.. that's a lot of CLI code (hope i'll find time to review it soon). |
|
This looks really nice! @zuiderkwast Did you consider actually using the first keypress that breaks out of the receive loop as input? Intuitively I just started typing but then noticed the first character is "lost". |
Thanks for trying it out. :-) Yes, using the "any key" as input would be ideal, but it is consumed by the readline lib (linenoise). I would need to look into modify it in some way then, but I didn't go that far. |
|
@yossigo The "any key" can be used as input if we change the following in linenoise. I don't know if it has any drawbacks. Probably it will just make input available that otherwise would be lost if the user is typing too fast. Is it worth it? WDYT? diff --git a/deps/linenoise/linenoise.c b/deps/linenoise/linenoise.c
index 1b01622c5..c6c496e34 100644
--- a/deps/linenoise/linenoise.c
+++ b/deps/linenoise/linenoise.c
@@ -257,7 +257,7 @@ static int enableRawMode(int fd) {
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
/* put terminal in raw mode after flushing */
- if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
+ if (tcsetattr(fd,TCSANOW,&raw) < 0) goto fatal;
rawmode = 1;
return 0; |
|
i've tested it and i see few things that could maybe improved:
|
This must have been after the last commit (Use the "any key" as input). The enter goes to the prompt, which goes back to "reading messages..."
That's expected. When the prompt is visible, linenoise is doing a blocking read() on stdin. It doesn't use select() to detect input on the socket here, since this is a separate library which is only concerned about line editing. Do you think I should break the abstraction of this lib and read push messages during line editing, or inject some way to do it, using ifdefs or something like that?
Right. This is easier to solve. How about using a different color for push messages? Cyan, magenta... |
|
Exactly :-) Sorry for the confusion.
Isn't it clear enough that when the "Reading messages..." is displayed, push messages are displayed continuously, but when the prompt is displayed, it can't be assumed that they are?
OK, for RESP3 we can use a prefix for all push messages. I think that's a good idea. For RESP2 though, the user can't really tell what's a "push" and what's a reply. There is no difference. That's why only a few commands are allowed in RESP2 pubsub mode. The user can disambiguate by looking at the replies. |
src/redis-cli.c
Outdated
| char numsep; | ||
| if (r->type == REDIS_REPLY_SET) numsep = '~'; | ||
| else if (r->type == REDIS_REPLY_MAP) numsep = '#'; | ||
| else if (r->type == REDIS_REPLY_PUSH) numsep = '>'; |
There was a problem hiding this comment.
aren't we introducing a breaking change (for scripts that work with redis-cli)?
i thought to do that only in interactive mode, but actually that would be confusing (someone experimenting with interactive in order to know how to write his script).
@yossigo please advise.
There was a problem hiding this comment.
This output is only for TTYs, so script shouldn't be affected unless they're trying to simulate a TTY (like we do in the TTY tests).
There was a problem hiding this comment.
It seems redis-cli --no-raw in scripts is affected, so it's breaking change for this use case.
There was a problem hiding this comment.
All other types have their own prefix, so it's odd that push doesn't. Push shares the prefix with array (1), 2) etc.).
OTOH, this is not coupled with this PR so I can move it to a separate PR.
There was a problem hiding this comment.
I spoke to Yossi, let's drop this > change, and add it in 8.0
i suppose you're right. testing the new last version and knowing that seems that it works right. looking for the another interesting thing i just noticed, that while in that subscribed mode, i'm getting another line ( |
Well, try HELLO 3 and then SUBSCRIBE x y z, then you'll see the
It is explained on the page https://redis.io/commands/ping/: "If the client is subscribed to a channel or a pattern, it will instead return a multi-bulk with a "pong" in the first position and an empty bulk in the second position, unless an argument is provided in which case it returns a copy of the argument." |
comment out the `>` push prompt
The reason is in reply-schemas-validator, the resp of the
client we create will be client_default_resp (currently 3):
```
client *createClient(connection *conn) {
client *c = zmalloc(sizeof(client));
#ifdef LOG_REQ_RES
reqresReset(c, 0);
c->resp = server.client_default_resp;
#else
c->resp = 2;
#endif
}
```
But current_resp3 in redis-cli will be inconsistent with it,
the test adds a simple hello 3 to avoid this failure, test
was added in redis#11873.
Added help descriptions for log-req-res, force-resp3 and
dont-pre-clean options, options was added in redis#10273
The reason is in reply-schemas-validator, the resp of the
client we create will be client_default_resp (currently 3):
```
client *createClient(connection *conn) {
client *c = zmalloc(sizeof(client));
#ifdef LOG_REQ_RES
reqresReset(c, 0);
c->resp = server.client_default_resp;
#else
c->resp = 2;
#endif
}
```
But current_resp3 in redis-cli will be inconsistent with it,
the test adds a simple hello 3 to avoid this failure, test
was added in #11873.
Added help descriptions for dont-pre-clean option, it was
added in #10273
|
@zuiderkwast maybe you can have a look at a sporadic error from the new test of this PR: maybe a timing issue (freebsd CI is notorious for being slow) |
|
I will take a look in a few days. |
|
I can't tell why this failed. This proc read_cli {fd} {
set ret [read $fd]
while {[string length $ret] == 0} {
after 10
set ret [read $fd]
}
# We may have a short read, try to read some more.
set empty_reads 0
while {$empty_reads < 5} {
set buf [read $fd]
if {[string length $buf] == 0} {
after 10
incr empty_reads
} else {
append ret $buf
set empty_reads 0
}
}
return $ret
} |





The message "Reading messages... (press Ctrl-C to quit)" is replaced by "Reading messages... (press Ctrl-C to quit or any key to type command)".
This allows users to subscribe to more channels, to try out UNSUBSCRIBE and to combine pubsub with other features such as push messages from client tracking.
The "Reading messages" info message is displayed in the bottom of the output in a distinct style and moves downward as more messages appear. When any key is pressed, the info message is replaced by the prompt with for entering commands. After entering a command and the reply is displayed, the "Reading messages" info messages appears again. This is added to the repl loop in redis-cli and in the corresponding place for non-interactive mode.
An indication "(subscribed mode)" is included in the prompt when entering commands in subscribed mode.
Also:
Fixes a problem that UNSUBSCRIBE hanged when used with RESP3 and push callback, without first entering subscribe mode. It hanged because UNSUBSCRIBE gets one or more push replies but no in-band reply.
Exit subscribed mode after RESET.