Have been using Elixir / Phoenix for a while but still I get confused with the role of GenServer and its use cases. Would love to know about it and its use cases in both web apps and as in general GenServer implementation
TL;DR Use them when You want concurrency.
Under the hood, Elixir and Phoenix uses a lot of GenServers. You can see them running with the observer.
GenServer is just a part of OTP (Open Telecom Platform), so it would be better to understand what is OTP. Mostly, it is a set of specialized processes, You can see them as design pattern for processes…
- state machine (gen_statem, or older gen_fsm)
- GenEvent (kinda obsolete in the Elixir world)
And even more specialized GenServer, Agent and Task …
You might even not notice them while using them.
For example, in Phoenix, each socket connection is powered by a GenServer process.
When You code modules, it’s like librairies of functions. But when You code processes, it’s like managing thousand (million) of Lemmings. Each process acts as primitive for concurrent programming.
I wonder about building third party libraries with genserver. I see alot libraries with genserver. What is benefit of genserver about packages ? I see they need to start with our app.
Some common use cases for
GenServer along with
Task which are built on top are:
Spawn processes to handle independent workloads.
Task.async makes it easy to run a function in a separate process and later
await the result.
init callback produces an initial state, and it can be transformed by each of the
Agent makes it easy to wrap up a state value in a process.
Instead of guarding a resource with a lock, let a
GenServer hold it as state, and use
GenServer.call to access it.
A crash in a
GenServer will be handled by its supervisor, which can restart it to hopefully get it back into a valid state.
To spawn, or not to spawn has some great advice on best use of processes.
If You implement a package, for example a caching micro service, You would want the cache server to bootup with your main application.
Building a package can include modules and functions, but can also include full working microservice. Also, when You build umbrella projects, You can consider each application as an independant package, started from one main entry point.
One good exercice is to implement a web scrapper because it implies to think concurently.
He starts by creating generic servers from scratch before going on to GenServers and that really helps you get your head around it. (He does the same for Supervisors as well.) Definitely a must-get book
I heard about Phoenix’s GenServers and it was what ultimately got me hooked on Phoenix/Elixir. I was previously a Rails developer and couldn’t figure out how to solve a concurrency problem.
My application was for a bot that had about 1000 or so users that would, at the same, log into a JS heavy site and perform about 10-15 minutes worth of timed actions. This was where GenServers came in handy.
I ended up making a GenServer module that would represent a user and hold a Hound() session as state. So when it was time for every user to bot the site concurrently, 1000 processes would spawn, each representing a user that was running a browser on a Selenium server. This way I was able to hold the state, and establish supervisors to monitor each process in case one crashed.