Hi all
When I create a channel like:
channel "videos:*", Rumbl.VideoChannel
It will start a process for this channel? If yes, then only one process will handle all incoming events?
Thanks
Hi all
When I create a channel like:
channel "videos:*", Rumbl.VideoChannel
It will start a process for this channel? If yes, then only one process will handle all incoming events?
Thanks
I think thereās a minimum of 2 processes for any given channel. There will be one PubSub process, and one process for each client/user.
When you create a channel like that it creates no processes.
However let me go through the whole process as I understand it (from debugging and reading a good bit of the code).
The client websocket/longpolling connects to the āSocketā that you made, that spawns off a new process, thus (1) process so far, for the open socket. That socket process then checks if it is allowed via your own code and such, do whatever you want, set assigns that will be given to all other topic processes too. That socket then checks the topic being connected to and spawns another new process for just that topic (and each new topic connected comes in the same socket process but then makes a new topic etcā¦). That topic process gets a copy of the socket assigns (this way you can do something like get the user from the database and store in an assigns for all topics to see). So at this point you have two processes, and one additional process for each extra topic.
Thanks
If I understood it correctly, then a topic like āuser:*ā will be spawned once for all users, each user/client has be connected over a persistent socket (which itself is a process, sure), but there will be no additional processes for each user:#{id}
topic, right?
Nope, a process is spawned for each topic for each user. You can join more topics from inside a topic though, and āthoseā will not create more processes, but anytime the javascript sides connects to a topic for every single user then a new process is created for that specific topic/connection by default.
Hmm, thank you, so., this can potentially become expensive⦠I am wondering, how we could send a single message to an opened socket connection, on a single users
topic but to an explicit single user
. I mean simply like responding is happeningā¦
I mean, you mentioned, that its possible to join an user to a topic without creating those processes.
So basically from JS channel = s.join('users')
Inside users one would join to user:id
but broadcasting messages wouldnāt reach the client side⦠because there is no channel with the topic user:id
definedā¦
If you broadcast to a topic unique to a given user, say "user:123"
, only that user will receive the message. If youāre asking how to message to a single user 123ās devices, then you can use Phoenix Presence, but we need to know more info to know what your exact usecase is. Generally itās just fine to broadcast to a private user topic since you usually want all tabs/devices the user has joined to receive the message.
Not too bad at all. Processās are overall cheap.
You need to make at least one topic, as it is āthatā that can then join others without extra processes. You can broadcast just fine once the topic you made registers to them, like a socket joins "users"
but that topic also internally joins "user:#{id}"
, then you could broadcast to "user:#{id}"
and that "users"
topic would get it just fine.
Hi @chrismccord thank you for your attention. Iāll try to explain the use case:
10 users, each on a single device. All of them connect are connecting to the backend via WebSockets.
(For each of those is a socket process created, so far so good)
Now all of them join the room:lobby
Another process is created, which holds the state of the channel and all its meta data.
Now each of them joins to the user:uuid
channel⦠As I understood, this will spawn another 10 processes (one for each wildcard uuid)
So, basically, the main question is, how send a single message to a particular user, (I could store a map like uuid -> socket
on some generic topic like users
?
To a particular user? Just MyEndpoint.broadcast("user:uuid", ...)
as normal.
What about that does not work for you?
Ok, this sounds very good, maybe you have some more info on this topic
? I would like to check out some example, to get my head around it. I mean how to join inside the a join, and what do I have to handle inside and so, or is it simple like that?
def join("users", %{"id" => id}, socket) do
join("users:" <> id, _, socket)
end
Itās at: https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#module-endpoint-api
To join youād actually do:
def join("users", %{"id" => id}, socket) do
MyEndpoint.subscribe("users:" <> id)
end
At which point this same "users"
process will get messages for "users:"<>id
, but it will not automatically forward them to the client, to do that you just listen for them (just like any other PubSub message, Phoenix Channels are just Phoenix.PubSub underneath) and then push them to the client however you want.
I think you gave me a good starting point to dive deeper now. Thank you!
If you need anything else, just ask.
Hmm, I think I understood how to subscribe to a virtual
topic. And to listen on the incoming events / firing events, seams to be clear. But the last problem I have is to understand how to
⦠push them to the client however you want.
I would like to push the message to the client over the āusersā channel, where the client joined initially to.
ā¦I wish there would be a simple API for like Endpoint.send(socket, payload, topic)
function, where the topic process could hold many sockets, but allow direct messaging to each separately. I mean it must work somehow, like handle_in ā reply to a single client, right?
Think of it this way:
broadcast
messages between them via topics they are subscribed toThus you just listen for the messages via normal handle_info
or whatever it was for sockets, then just push
the message back out to itself just like you do any other message.
An Endpoint.send(...)
makes no sense as you can already push(..., socket, ...)
anyway, which is the same thing.
Oh Yeah, now I got it⦠push
is what I was looking for all the time⦠many thanks. Really strange that this feature is only mentioned in in the interceptions and outgoing events section. This makes it much much clearerā¦
So, I could basically manage the sockets by myself somewhere in a custom GenServer or so, and broadcast some messages to all sockets, and some for specific users, just with push⦠you made my day (night actually) Thanks!
Easiest way for specific users is just to have them join a topic all on their own with their user ID or so, like you user:uuid
above did, then just broadcast to it.
Donāt use any custom genserverās, not at all useful since you can do it all (and safer and faster) via Phoenix.PubSub.
Iāll do it like you said for my MVP, but its good to know that those options exists and Iāll definitely play around with it when the time comes