When and where to use genservers?

So I already saw these kind of posts but they didnt answer my question.

When and where do you guys use a genserver? Could anyone drop me an example (in mix, not phoenix)
Like for a library XYZ that does XYZ because XXX has to do ABC

Briefly Usage Guide — briefly v0.4.1 uses a GenServer to track open temporary files tied to a resource, and remove them when those processes go down.

Absinthe uses GenServers for inter-server pubsub to make subscriptions work.

ExAws uses a GenServer to manage refreshing credentials for AWS in the background.

Broadway uses genservers to manage pulling items down from producers like cloud pubsub for processing.

Basically, if you have an activity that needs to be going on, you probably want a genserver.

6 Likes

An example of them being used simply to store state is ExUnit.Formatter. A formatter is a GenServer that receives lifecycle events at various stages of a test suite run and and stores up info to be formatted and printed when it’s finished, like the results of each test. I’m assuming this is done to decouple formatting from the test runner making it easier to implement custom ones as opposed to having to thread a %Formatter{} through every test. But don’t quote me on that :slight_smile:

1 Like

Thank you!

Where or When could I use GenServer when it comes to web backends?

I have found that the typical “web backend” type things that I encounter generally don’t require me to use GenServer directly. For example, you may need to do some sort of job processing, which you could do using GenServer (or similar), but there’s also some pretty mature libraries out there which give you a higher level abstraction (looking at you, exq, Oban, etc). If you wanted to roll your own anyway, then this is one use case.

As another example, I once made a board game that could be played in the browser. It used GenServer to keep track of the state of the game, which was shared among all the connected players and included things like:

@type t :: %GameState{
          board: list(BoardLocation.t()),
          id: binary(),
          last_move: list(BoardLocation.t()),
          marble_colors: map(),
          marbles: list(Marble.t()),
          players: list(String.t()),
          connected_players: list(String.t()),
          seconds_remaining: non_neg_integer(),
          status: game_status(),
          timer_ref: nil | reference(),
          turn: nil | String.t(),
          turn_timer_ref: nil | reference(),
          winner: nil | String.t()
        }

It depends on what “web” means to you. If you are responding to HTTP requests and that’s it then you probably wouldn’t use a GenServer. If you are maintaining a websocket connection or a database connection (in order to serve either HTTP or WS) then you’ve got them. If your HTTP API needs any of ExAws / etc then you’re relying on them.

1 Like

I personally use Genserver in places where it or something it works with only uses a single process. What I mean is that multiple requests are not sent to it from different places.

For example, a Genserver checks if there is a file that has been created for more than 10 minutes and deletes it, or searches the ETS table every 10 seconds and stores the information in the Postgres database.
I use ETS to read and write state at the same time with many concurrent requests.

If I am in a wrong way, please let me know

When (not) to use a GenServer

https://hexdocs.pm/elixir/1.14.3/GenServer.html#module-when-not-to-use-a-genserver

1 Like

I don’t how much this adds to the conversation but I sort of think of it at a very simple level.

If it makes sense to have an agent do the work it should be a genserver much like I am going to probably use cowboy instead of fiddling with :inets and :httpd.

If it is a task then a genserver doesn’t make sense and should just be a “normal” Module.

Fb and free learnings welcome :slight_smile: