Skip to content
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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

adrianke
Copy link

@adrianke adrianke commented Nov 1, 2024

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.

Copy link
Owner

@whatyouhide whatyouhide left a 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:

  1. We need to handle :ping calls when the gen_statem is in the disconnected state.
  2. We need tests.
  3. Instead of sending a PING command with a message, could we just keep a queue of pending PING commands, and for every PONG that the gen_statem receives we send it to the next caller waiting in the queue? Redis is single-threaded so it will reply to PINGs in order anyway.

Comment on lines 236 to 246
{:ok, task_pid} =
Task.start(fn ->
res =
receive do
{:pong, ^random_string} -> :ok
after
5000 -> :error
end

:ok = :gen_statem.reply(from, res)
end)
Copy link
Owner

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.

Copy link
Author

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?

Copy link
Owner

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"
@adrianke
Copy link
Author

adrianke commented Nov 4, 2024

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:
And I've added a handler for the disconnected state, and removed the need for a subscription ref from the function signature.

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.

2 participants