Dynamically change the type of GenServer

I have discovered the following :gen_server.enter_loop/3 link. This can be used to change the behaviour module of a GenServer. I am curious why this behaviour was never exposed in Elixir.

I am currently using it to turn a generic HTTP2 stream handler into a user specific one that can handle bi directional streaming. It’s turning out to be quite a nice API

defmodule Ace.HTTP2.StreamHandler do
  use GenServer
  def start_link(config, router) do
    GenServer.start_link(__MODULE__, {config, router})
  end

  def handle_info({stream, message}, {config, router}) do
    request = Ace.HTTP2.Request.from_headers(message.headers)

    handler = try do
      router.route(request)
    rescue
      _exception in FunctionClauseError ->
      Ace.HTTP2.Stream.DefaultHandler
    end

    case handler.handle_info({stream, message}, config) do
      {:noreply, state} ->
        :gen_server.enter_loop(handler, [], state)
    end
  end
end
3 Likes

Ok, so after experimenting with this for a little while I think it is great way to model things that change state in a simple manner. for example something that changes state only once. I have now used it three times in my codebase and two of those are examples of things that changed state only once. a client or server have a handshaking state followed by a running state.