arnodirlam

arnodirlam

Subscribe all clients/presences in one channel to an external topic

We have a use case where we want to route an incoming call to all online users within a channel (“lobby”). Each of these users (“candidate pool”) can either accept or decline the incoming call. The first user accepting the incoming call will be connected and the selection process ends (first come first serve, max. 1).
Before anyone accepted the call, each candidate still in the pool (= not declined yet) should know who else is still in the pool.

Since channels and Presence are made for that, my intuition is to implement the system using it.
My idea is to create an external topic (new channel) for the incoming call, then add all candidates (from the “lobby” channel) to it, and use broadcast Presence diffs whenever the pool’s state changes. When a user accepts the incoming call, the external channel is immediately closed.

However, I’d like to avoid broadcasting to all users in “lobby” to join the external channel (client-side roundtrip), because of performance, reliability and security. I’d like to keep the logic server-side, ideally preserving the multi-node attributes that channels+presence gives me out-of-the box.
If I understand correctly, this forbids approaches using the “lobby” subscribers’ PIDs directly.

So my approach would be to broadcast a message to “lobby” with the external channel’s topic, then intercept the broadcast, let handle_out have each subscriber join the new channel, and cancel the message going to the client. All server-side. Once all candidates have joined the external topic, standard channels+Presence broadcasting can handle the rest.

Is this the best approach for the given use case?
Am I overlooking something?

On a sidenote, the phoenix JS-client will not “know” it’s subscribed to the external channel, so I have to either use its onMessage callback, or manipulate the topic of each outgoing message server-side using intercept and handle_out, correct?

Thanks a lot in advance for any feedback! :slight_smile:

Marked As Solved

OvermindDL1

OvermindDL1

Precisely! :slight_smile:

Also indeed. :slight_smile:

Presence is for presence information, not for broadcasting. If you want user channel to listen for specific things then have them join another specially named topic then broadcast to that. I do not mean have them join a new topic from the javascript side or even to spawn a new process, but literally just call MyServer.Endpoint.subscribe("new:topic:thing:o'whatever"), and when you want them to stop listening on that topic then just call MyServer.Endpoint.unsubscribe("new:topic:thing:o'whatever"). Anything broadcast to those new topics and not the ‘channel topic’ will not appear in handle_in/handle_out, but rather will appear in handle_info with a Phoenix.Socket.Broadcast structure, use it like this:

  def handle_info(%Phoenix.Socket.Broadcast{event: "notifications:"<>_ = event, payload: %{notifications: notifications}, topic: _topic}, socket) do
    offset = 0 #socket.assigns.offset
    pageSize = length(notifications) #10
    msg = %{
      offset: offset,
      pageSize: pageSize,
      notifications: notifications,
    }
    push socket, event, msg
    {:noreply, socket}
  end

For example I use this in my notifications channel topic, then the notification internally registers to certain other things depending on which notification groups they are assigned to. :slight_smile:

But yeah, presence is literally just for tracking presence in the group, not to communicating to it, for that you should subscribe to the new topic as well and broadcast to that. :slight_smile:

Also Liked

OvermindDL1

OvermindDL1

Exactly on both. :slight_smile:

Yep, handle_info just handles messages to this process that it does not know what they are, so that ‘you’ can handle them straight. :slight_smile:

You might want to have a catch-all handle_info at the bottom of the handle_info’s too so a process does not crash if it happens to get a message it does not know (I log them).

No problem, I delved into the code for them when I started using them a while back, so it is good to spread the knowledge. :slight_smile:

OvermindDL1

OvermindDL1

You can have more than one presence setup per channel as well, just have to give each a unique ID, but I use this quite often, just as a note. :slight_smile:

But say you have N users in a lobby/pool, a call is made to this pool so a message is ‘broadcast’ to the topic id of the lobby/pool to pop up a message on the users interface or so. The first to accept it sends a message back to the call handler thing that has it join the call process while also sending a message to the other clients that it was accepted elsewhere with whatever other useful data. You may not even need presence for this unless you want to know who all is waiting rather than just broadcasting all willy-nilly (which is fine really ^.^). :slight_smile:

But yeah, I’d have a user connect to a call when it is accepted, not when it is offered. You could even have them all join a presence so you know who is waiting for a response, and as they deny it they leave the presence, until one accepts then they all drop off when they get the message that it was accepted by someone else. :slight_smile:

arnodirlam

arnodirlam

Thanks for your fast reply and also commenting on the use case :slight_smile:

You can have more than one presence setup per channel as well, just have to give each a unique ID, but I use this
quite often, just as a note. :slight_smile:

Nice to know! I guess you pass in the original channel pid and another topic, similar to here?

You may not even need presence for this unless you want to know who all is waiting […] (which is fine really ^.^). :slight_smile:

You might be right that the info is not needed. However, I think it would be really useful for the users to know, and I’m also eager to wrap my head around this use case of Phoenix, testing whether it could really work like I’ve described in my question, keeping all the multi-node niceties in place :sunglasses:

You could even have them all join a presence so you know who is waiting for a response

This is exactly what I’m trying to achieve. Ideally with broadcasts to only those users in that second presence.
You’re talking about another Presence within the same channel, not a separate channel, right?

So I assume that

  1. I can just copy contents of one Presence to another, without having to deal with PIDs or anything internal, and it just works?
  2. All Presence diffs are sent to the whole channel, no matter if each subscriber has already declined, or even entered after the initial broadcast. Or can I broadcast to only those subscribers who are in the Presence?

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call t...
New
yawaramin
In the Dialyzer docs ( dialyzer — OTP 29.0.2 (dialyzer 6.0.1) ), there is a way to turn off a specific warning for a function: -dialyzer...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement