[erlang-questions] Beginner trying to figure out idiomatic OTP architecture

Mark Allen mrallen1@REDACTED
Wed Mar 23 15:04:56 CET 2016


One thing to be wary of is that in a distributed Erlang environment, using global process identifiers introduces significant latency compared to a local identity because the global module uses locks across all Erlang nodes to achieve consensus on the identities that have been assigned both at process start up time and at identity to PID lookup time.  
Most Erlang applications "in the wild" avoid global when at all possible. 

    On Tuesday, March 22, 2016 8:42 AM, Matthew Shapiro <me@REDACTED> wrote:
 

 Neat, that definitely makes things less complicated to talk to processes managed by another supervisor!
On Tue, Mar 22, 2016 at 4:48 AM, Oliver Korpilla <Oliver.Korpilla@REDACTED> wrote:

Hello, Matthew. I'm a beginner, too. I just perked my ears when you wrote about the "which_children()" call... The gen_xyz() modules all follow a similar startup logic that allow you to register the child under an ID. The way you see used in "Learn you some Erlang good" is the easiest one, the local registration ({local, <name>}) where <name> must be an atom. You can, however, use other registries - like "global". Google "man erlang global" for more details about that registry. There an arbitary expression is good enough as a name. This is hugely advantageous for many applications, including your own, as you can use something like {<atom>, <number>} or {<atom>, <string>} as process name. With global:whereis_name you can ask for the needed PID to send messages to. It returns undefined if it doesn't exist. So, instead of asking the supervisor about the children, you just call whereis_name with the computed ID you would be looking for, like {user, "DanWahlberg69" } and if you get something else but undefined, you can directly talk to the worker you are looking for. This should keep your supervisors simple. All you need is a scheme to generate unique names and you are set.  Hope this helps,Oliver Gesendet: Dienstag, 22. März 2016 um 04:06 Uhr
Von: "Matthew Shapiro" <me@REDACTED>
An: erlang-questions@REDACTED
Betreff: [erlang-questions] Beginner trying to figure out idiomatic OTP architectureI am trying to learn Erlang in order to create an application that seems to check off all the boxes of the Beam VM (low latency requirements, extremely concurrent, long lasting connections making hot code swapping desirable for upgrades, etc...).  In order to learn I've gone through most of Learn You Some Erlang For Great Good, and so far have really been enjoying the process. I am now at the point where I want to test some of this knowledge out, and I thought a good idea was to create a (basic) IRC server (as I've written them in the past in other languages, and it seemed like a good use case for Erlang).  Basic idea is to support allowing users to connect, set a nickname, connect to channels, send messages to channels, and send messages to users. However, I am a bit confused on the proper way to architect an OTP application and hoping that my current idea of how to architect this is correct or not.  Also, I find rubber ducking helps :) The high level supervision tree I have floating in my head is to have: * application** app_supervisor*** tcp_listener*** handshake_supervisor**** handshake servers (dynamic)*** user_supervisor**** user servers (dynamic)*** channel_supervisor**** channel servers (dynamic) My thinking is the tcp_listener, handshake, user, and channel modules would each be gen_servers, and the 4 supervisors would be standard otp supervisors. The app_supervisor would have a one_for_one spec while user_supervisor, chandshake_supervisor and channel supervisor would have simple_one_for_one spec since they can spin children up and down dynamically based on users connected and channels with at least one user in it. The flow I have in my head is: 1) tcp_listener is a server that waits for connections, accepts them and tells the handshake_supervisor to spawn a new handshake server for the accepted socket (and changes ownership of the socket to the handshake server.2) The handshake server handles the IRC handshake, and when the user requests a nickname it asks the user_supervisor if any children exist with the id matching the requested nickname. 3) If the nickname is available, the handshake server tells the user_supervisor to start a new user server with the accepted socket and nickname, sets the user server as the socket owner, and then the handshake server terminates4) When the user server is started, the user_supervisor would set its id of the child spec to be the user's nickname.5) When the user joins a channel, the user module sends the accepted socket and the users nickname to the channel_supervisor and asks it to send it to the correct channel.  The channel_supervisor will look for a child process with the id matching the name of the channel, and if none exists it will create a new child with the channel name as the id in the child spec.  It will then send the child process with the matching id/name a message with the users nickname.6) When the user leaves a channel it will call on the channel_supervisor to send a message to the child process with a matching id/name with the nickname of the user leaving the channel (or disconnecting).7) The channel server will keep a state with a list of connected users, and when a join, leave, or channel message is received it will modify the client list as needed.  8) When required (user joins, user leaves, someone says something, etc....) The channel server will send a message to a specific user by calling the user_supervisor to send a string to a child process with an id matching the nickname of the user, and send that child process an erlang message with the irc message to send to the user.  The user server will then take that, translate it into the IRC protocol and send it to the socket.9) On client disconnection, the user server will announce to the channel supervisor that it has disconnected, and the channel supervisor will tell all children it no longer is connected to the channel.  So the problem I have on this architecture is it requires a lot of logic in the supervisors (which I am not sure is a good or bad thing).  It also seems to invite myself to race conditions due to all the supervisor:which_children() calls that would be required to identify the correct child process to send a message to, since theoretically a child process could die between a which_children() and actually sending the message.  It also means going through several layers of supervisors in order to find the process another process needs to communicate with (for example, user server would have to ask the user_supervisor to ask the app_supervisor what process the channel_supervisor is, which would then have to ask the channel_supervisor what process the correct channel server is).  This seems hacky but I am unsure of how to work around that. Am I on the correct path with this?  Is there an easier way to facilitate servers talking to other servers managed by other supervisors? Thanks._______________________________________________ erlang-questions mailing list erlang-questions@REDACTED http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
erlang-questions@REDACTED
http://erlang.org/mailman/listinfo/erlang-questions


  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20160323/b0cba183/attachment.htm>


More information about the erlang-questions mailing list