1

What is the best way to access the state of a node from another node?

I have an application developed with Phoenix Framework(elixir phoenix). I want to run this application in multiple nodes to manage the traffic. I am leveraging the power of sockets provided by phoenix and so this application creates lot of sockets.

Our application has the need to store the presence information of the user. Taking help from this answer, I had created a watcher that maintains the presence information in the state of the watcher. I have to check whether the user is online by accessing the presence information.

When I do multi-node setup, users might be connected to any node. In such case, to check online status of a user, I need to access the presence information from all the nodes. And this operation is going to be very frequent.

What is the best way to accomplish this state access across nodes?

Can ETS be of any help here?

Can I use Genserver.call({node, name}, :identifier) to get state? Is it a blocking call? Will this make the node slower?

Any other efficient way of doing it?

Community
  • 1
  • 1
Jebin
  • 702
  • 13
  • 33
  • Why not run the watcher on a single node? Have the login/logout event send messages to that watcher. You then only need to monitor that one watcher. – GavinBrelstaff Mar 16 '16 at 07:46
  • 1
    @GavinBrelstaff: That works if you're OK with the risk of a single point of failure. – Cody Poll Mar 17 '16 at 23:08

1 Answers1

3

You need to expose the information that you want to share with other nodes through an API. In this case each node would need to have an API to expose the user status to other nodes. You can approach this problem twofold:

  1. Active sharing: The node that contains user state actively sends the state to other node (or to a form of cache) in response to some event (e.g. when the user connects, disconnects, every hour, ...)

  2. Passive sharing: Other nodes query the node that has the user state information when they need that information.

In both cases you can have many possible designs.

For example, in the first case you could have a broker (like RabbitMQ or ZeroMQ) which accepts the notifications and stores them so that other nodes can query for them or sends them around according to some rules. Also if you opt for storing the notifications in an ETS table on the node, such ETS table would essentially work as a broker. So the ETS table falls into the first category. The process that contains the user state stores the information in ETS and from there another process can query it or alternatively the process that owns the ETS table can send the notifications around according to some rules.

For the second case, you would expose an API, probably in the form of a call to the gen_server, so that the other node can retrieve the user state directly from the gen_server where it's stored. Then you can call the API synchronously, e.g. using rpc:call. Or you can call it asynchronously with either spawning a new process to handle the call or using rpc:async_call.

Which design to choose is the important question which you need to answer yourself. If the user state changes often and you only need to query from time to time then the second variant may be more efficient. If the user state doesn't change often and it would be good to cache it from the performance perspective then the first option may be considered. You also need to consider additional complexity and likely other requirements.

In your specific case the first option - send notification when user is online - seems to fit better. The exact implementation may depend on how you want to use that information.

Greg
  • 8,230
  • 5
  • 38
  • 53
  • 1
    At an implementation level, a `:pg2` group would be an appropriate mechanism for broadcasting (as in your first approach). On each node, have an ETS-backed GenServer subscribed to the group, and then each node can broadcast to the group members any time there's a user state change. Then each node has it's own copy of the user state information. – Chris Meyer Mar 16 '16 at 14:14