Search code examples
rediselixirphoenix-frameworkphoenix-channels

Streaming from a redis channel through a phoenix channel


I am currently trying to replace with a small phoenix app. What I need to do is get information from a channel and stream it to an client. I have been attempting to use Redis.PuSub and the Phoenix Redis adapter, but haven'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 channel's 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 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


Solution

  • So in order to solve this issue I did the following.

    Firstly I setup Redix.PubSub as a dependency as per the docs. Then in the channel I did :

    defmodule MyApp.ChannelName do
      use Phoenix.Channel
    
      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
    
      # Avoid throwing an error when a subscribed message enters the channel
      def handle_info({:redix_pubsub, redix_pid, :subscribed, _}, socket) do
        {:noreply, socket}
      end
    
      # Handle the message coming from the Redis PubSub channel
      def handle_info({:redix_pubsub, redix_pid, :message, %{channel: channel, payload: message}}, socket) do
        # Push the message back to the user
        push socket, "#{channel}", %{message: message}
        {:noreply, socket}
      end
    end
    

    In my case I required the user to sign up with a channel with some name e.g. channel_my_api_key. I would then start listening on the redis channel channel_my_api_key and stream the information back to the user via the push function. Note broadcast can be substituted for push.

    Credit also to Alex Garibay from the Elixir forums that helped me get to the solution. You can find the thread here.