Linking to phoenix pub/sub processes

Hi there,

I am writing my first Elixir application. My application relies heavily on Phoenix channels.

Here is what I am trying to do:

Allow a user to “chat” to my application through Phoenix channels. Messages are sent from the client, handled in the channel and forwarded to my application. My application can also respond back to the Channel and send messages to the client. I am struggling out how to define that relationship.

I am using the terms socket and channel interchangeably here, hopefully that isn’t confusing anyone. My beginner knowledge of Elixir is still grasping at what to call “things”. I have to keep reminding myself that there are no objects…

Here are the approaches I have taken so far:

When someone joined my channel, the first approach I took was to create a link between the socket and my custom GenServer process by using socket.assign in the channel and passing the channel process id to my custom GenServer init and keeping it in the GenServer state. That allowed me to send messages back and forth between my custom Module and channel client. However, I had no way of knowing when the socket connection was closed - at least based on my begginer knowledge of Elixir and I was quickly left with processes that were communicating to a Channel process that no longer existed.

The other approach I was thinking of was to tie my GenServer process directly to the channel process using spawn_link. I figure that way I would get notification when the channel is closed. I also noticed in observer that if I kill the PubSub process, all the sockets processes are created again. So maybe this would be a better way to manage the linking of my custom process.

Currently my Module is just a GenServer and will probably become a Supervision tree of its own as my application grows. I am still finding my way there…

Cobbling this question together made me realise how much I still have to learn, but learning Elixir has been so much fun so far and really makes sense to me. Thanks for your help.

BTW - I am loving learning elixir, so much fun! And no configuration nightmares in getting setup…

1 Like

May be I do totally understand you wrong here, but why linking processes at all?

When a message comes over the Channel you do handle it in your channel, perhaps delegating some work to your GenServer by sending another message over to it by name or PID.

If your GenServer has an answer to a previous request it does use the usual OTP mechanics to reply.

If your GenServer does think that a message should be received by all subscribed clients, it just broadcasts it to the according topic.

It sounds like you want a monitor rather than a link:

https://hexdocs.pm/elixir/Process.html#monitor/1

1 Like

From your description it isn’t clear why you need a Genserver for your application. Is there a reason that a genserver is actually needed, could you instead implement your logic with plain functions or is there a runtime concern that you need to handle? Saša Jurić has a great article on this topic. Here are his main points:

  • Use functions and modules to separate thought concerns.
  • Use processes to separate runtime concerns.
  • Do not use processes (not even agents) to separate thought concerns.

Here’s the full article: http://theerlangelist.com/article/spawn_or_not

2 Likes

Thanks for the replies…

I did a pretty average job explaining my thought process about my current state of play, so hopefully the following will help explain why I am doing what I am doing.

  • My code base is definitely going to expand for my application (which is currently represented by the simple GenServer). But I am just trying to figure out how I can have the cleanest separation between Phoenix and my core code. I may use my application in a nerves based project at a later date (minus phoenix). So it makes sense to me to keep my code separate, so that I can easily integrate it into my Nerves build at a later date.

  • The reason I am using GenServer is that each chat channel spawns my application (currently represented by my GenServer - but will end up being a Supervision Tree of its own). I am keeping it as just a GenServer for now while I figure out how best to deal with how I communicated between the channel and my GenServer.

  • The purpose of my GenServer is to represent an computer based opponent who has properties like health levels, hunger levels etc which can be effected by messages sent from the client via the channel (and then passed onto the opponent) and of course the opponent can send messages back to the client.

  • Depending upon what state the opponent is in, their state might modify over a period of time. For example, over the next 10 seconds their health might decrease by 10 points. My current thinking around this is that the server is responsible for updating the opponents health and reporting back to the client via channels (maybe every second)… I would like to keep as much code off the client as possible so that my source code is as private as possible.

So that’s the kind of direction I am headed in and this is a pretty rough update on where I am at.

Thanks for the links to all the articles… still so much to learn!

1 Like

BTW - thanks for the link to Sasa Juric’s article… That has set me on a whole new path as to whether I needed to spawn or not… and so far I have been able to rewrite my application to not have that extra GenServer level I was referring to.

1 Like

:thumbsup:

Sounds like you’re on your way to a nice architecture :smile: did you have any further questions?

errrrr… yep… :grin::grin:

Hmm? Elaborate your new example that does not work then?

Came across this 3 years down the track. I think I was being sarcastic due to my beginner level with Elixir… Nothing like reflecting on posts from the past and realising what you thought would be hilarious, was nothing but confusing!! Hope all are well.

1 Like