-
-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ping command for PubSub connections #274
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is gonna be a useful addition. However, few notes:
- We need to handle
:ping
calls when the gen_statem is in thedisconnected
state. - We need tests.
- Instead of sending a
PING
command with a message, could we just keep a queue of pendingPING
commands, and for everyPONG
that the gen_statem receives we send it to the next caller waiting in the queue? Redis is single-threaded so it will reply toPING
s in order anyway.
lib/redix/pubsub/connection.ex
Outdated
{:ok, task_pid} = | ||
Task.start(fn -> | ||
res = | ||
receive do | ||
{:pong, ^random_string} -> :ok | ||
after | ||
5000 -> :error | ||
end | ||
|
||
:ok = :gen_statem.reply(from, res) | ||
end) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We won't need the task here if we go with a queue of pending clients.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the feedback.
Would the caller get an :error
after 5000 ms without the task?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The flow to implement here is using gen_statem timeouts and processe aliases, see
Timeout specifies how long to wait for a response. If no response is received within the specified time, this function returns timeout. Assuming that the server executes on a node supporting aliases (introduced in OTP 24) the request will also be abandoned. That is, no response will be received after a time-out. Otherwise, a stray response might be received at a later time.
from the gen_statem
docs. Basically you don't care about timeouts, you just reply to every pong and BEAM throws away the responses for procs that timed out already
This allows for periodic checking of the underlying TCP connection. According to the Redis documentation, PING is one of very few commands that can be issued on a pubsub connection: "Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional SUBSCRIBE, SSUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, SUNSUBSCRIBE, PUNSUBSCRIBE, PING, RESET and QUIT commands"
I've added some tests, and actually discovered that the reply format is different if you're subscribed to any channels or not. I've also removed the task, and replaced it with a callback that is sent after 5000 ms. EDIT: |
This allows for periodic checking of the underlying TCP connection.
According to the Redis documentation, PING is one of very few commands that can be issued on a pubsub connection:
"Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional SUBSCRIBE, SSUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, SUNSUBSCRIBE, PUNSUBSCRIBE, PING, RESET and QUIT commands"
I was not sure if the chosen flow is the best one, ie. sending a serialized PID as part of the payload and using that for sending the reply back to the waiting task.