Elixir. Process Registry. Sockets and gproc.
Distributed Systems Development A-Z Guide.
Give us a message if you’re interested in Blockchain and FinTech software development or just say Hi at Pharos Production Inc.
Or follow us on Youtube to know more about Software Architecture, Distributed Systems, Blockchain, High-load Systems, Microservices, and Enterprise Design Patterns.
Last time we have looked at process registry with ETS lookup. That was freaky cool but what should we do with all that stuff? Let make it more interesting. This time we will use a process registry to run socket worker. The app will listen to a socket(only one for the sake of simplicity) and respond with a dummy message.
- Elixir. Process Registry. One-node pool.
- Elixir. Process Registry. Dynamic workers.
- Elixir. Process Registry. Erlang Term Storage.
Sockets
Take a look at observer screenshot. On the top of the supervision tree, there is a tiny process — our listener. It was started by an application supervisor and now listens to incoming connections.
Let’s add two new packages to compile-time dependencies — :gporc and :socket. You can find more on the screenshot but we will talk about them in future articles.
Gen_server
Let’s replace our Process Registry on to battle-tested erlang’s library called Gproc. All we should do is to change via tuple. Else is the same. :n — means name, :l — means local. Every process will be registered locally on a node with a unique name.
Application
Application module starts socket listener in a supervision tree. Simple enough. We pass only one parameter — port. Surely port should be passed in some other less stupid way, but this time we add it through initialization parameters for the sake of clarity.
Socket Listener
Socket listener is not a gen_server as you have been expected. But it has similar API to make it possible to use from a supervision tree. For now, we have only one function — start_link with a port parameter. Start_link spawns a new linked process. We have seen it in application supervisor. This is a dedicated process which listens to the port. Socket sits on top of inet application, you can find extensive documentation here inet
We start an infinite loop in the init. When a connection is established we spawn a new process with a worker inside and back to listen to the next connection.
Now the most interesting part of the module. We should listen to messages and send them to a worker.
We have Socket receive case handler. In case of nil we pass through the function. In case of closed and halted connections we can skip and return just :ok atom, we don’t care for now. When we receive data we send a cast message to the worker. We send cast because we don’t care about the return value, it will be returned by a socket library. We send a cast message to a process which is registered globally via :gproc. :l — means locally on the node, :p — means property and let us set key/value pair for a process, other processes can set a name and value on their own.
Socket Worker
Start_link has been started by a Socket Listener. In init callback, we register a new process under :socket_listener atom with :p and :l keys. When worker receiving cast messages it can return values asynchronously by Socket library. That’s it!
Let’s Try!
Let’s run one terminal with a listener.
And another terminal with a telnet connection. As you can see our listener has started a new worker! Cool!
When we send a message to the application we can see it now! Socket listener works as it should.