James-Byrne
Streaming from a redis channel through a phoenix channel
Hi,
I am currently trying to replace action-cable with a small phoenix app. What I need to do is get information from a Redis channel and stream it to an ember client. I have been attempting to use Redix.PuSub and the Phoenix Redis adapter but havn’t been able to fully cover the functionality we currently have.
The current functionality works like this :
- Our server receives a request from a user and logs some output to a Redis channel
- That channels name is a combination of a string and a key
- The Ember client then makes a request to action-cable with the same key
- Action-cable then streams the logged information from the Redis channel with the same name
What I need to know is how to start listening to a Redis channel with a given name when the user makes a request & stream that information continuously to the client. I’ve managed to get one or the other using but not both.
I’ve been banging my head of this for over a day now so any help at all is massively appreciated.
Cheers
Most Liked
alexgaribay
I’m not quite sure if I am correctly understanding what you’re trying to do so please correct me if I’m wrong. You are wanting a user to join a channel with a given topic, phx:Elixir.TpPhoenix.PubSub for example, and want that user to be able to listen to messages being published to Redis PubSub with that same channel/topic name.
Ultimately, the channel code is just a GenServer with some extra sugar on top. Redix PubSub subscribes a PID to a stream of messages and you can handle messages sent to PIDs in a GenServer with handle_info. So the code I gave earlier was only the part of handling the message coming from Redix. You’d do the broadcast to your channel topic inside that method.
Here’s how it should look:
defmodule TpPhoenix.LogTailChannel do
use Phoenix.Channel
require Logger
def join(stream_name, _message, socket) do
# Open a link to the redis server
{:ok, pubsub} = Redix.PubSub.start_link()
# Subscribe to the users stream
Redix.PubSub.subscribe(pubsub, stream_name, self())
{:ok, socket}
end
# Handle the message coming from the Redis PubSub channel
def handle_info({:redix_pubsub, :message, message, redis_channel}, socket) do
# do something with the message
# Push the message back to the user over the channel topic
# This assumes the message is already in a map
broadcast! socket, "live_log_#{redis_channel}", message
{:no_reply, socket}
end
end
Keep in mind that this example only accounts for using PIDs. The user may lose connection at some point and reconnect again with a different PID. In my use-case where I do something similar to what you’re trying to accomplish, I have a separate process managing the subscriptions where I keep the mapping Phoenix Channel to Redis PubSub Channel. That process broadcasts updates to the channel topic rather than relying on socket PIDs.
benwilson512
I’m confused. If you’re trying to replace action cable entirely why bother with redis at all?
alexgaribay
Glad to hear you got it working.
I was speaking about tracking. For your use-case and how you’re using PIDs, I don’t think it is something you need to worry about. Just keep in mind that if a client loses connection, it’s likely a new process will be spawned and it will have a different PID. You’re subscribing the PID when a client joins, which is something I can’t do for my use-case, so you should be alright.







