2
votes

Cowboy will spawn process for each request (in this case it is websocket connection, event source request or long polling through ajax).

Sending messages between users are resolved simply by sending message to appropriate process representing the connection to that user (if you have two users and both have websockets support, than there are 2 processes, each representing websocket connection).

Lets say i have 2 users (Foo, Bar).

Foo wants to send message to Bar, so the Foo process must somehow to obtain pid that is associated with cowboy process representing connection to user Bar (so he can send regular erlang message to him - the message is internally sended to user webbrowser).

But what happened when Foo obtained the pid and the pid will become invalid, because the user Bar will reconnect in the meantime (reconnect means that the process associated with Bar was terminated and because Bar connects again, he gets new process)?

Bar reconnected because of network problems.

That means if Foo will send message to Bar (Foo has pid of process, that was terminated already), the message will never be delivered.

The first solution is that because the message should be probably persistent (like messages on facebook for instance), you will always save it to DB before you send it to the user. When the user connects, there must be done some synchronization, because even if he was 99% of time online, there could be massages he doesn`t have. So Bar will gets message from Foo when he sync after reconnect (message will be pulled from DB).

NOW THE REAL PROBLEM IS: what to do if Foo will have that invalid PID too long, that he will send some messages even after Bar reconnects and performed sync? The message for Bar will be stored in database, but because it was stored after Bar did sync, it will not be delivered.

3
You probably want to use a message passing framework like RabbitMQ.Stephan Dollberg
Since it real time communication, you don't want to deliver messages in the wrong order. Take skype as an example. No new messages shd be sent to Foo, unless all old messages are delivered in the order. Timestamps will help here.Muzaaya Joshua
The msg sending daemon must know who is on or off before attempting a send. Then it stores those messages = #msg{from,to,msg,timestamp}. When user reconnects, it ensures that he/she first receives all old messages in correct order before an new msg is sent to them.Muzaaya Joshua

3 Answers

1
votes

As you have identified - holding a PID as a user identifier is not a good solution, as it is inherently ephemeral. I think a better solution will be for user Foo to hold some persistent User ID which will identify user Bar no matter if he is connected or not.

You can keep a mapping from User ID to PID using ETS or DETS (supporting persistence), and send a message to the PID currently registered to the permanent User ID.

0
votes

So foo and bar should monitor each other. If one process die, the other one will get the message {'DOWN', Ref, process, Pid2, Reason}. And as Uri says, you can dedicate a process to the maintenance of the routing table.

0
votes

You can use the gproc lib. It's does use ETS to register, monitor, send messages and other processes. You can register the process with properties, unique names and even counters and query for them using the power of ETS queries. The APIs are really complete.

I think that if you want some guarantee of delivery you need to do it by yourself.