
Startup hook pattern (Erlang) - _nato_
http://blog.snailtext.com/posts/startup-hook-pattern.html
======
qohen
The idea presented in the linked blog post, of having a gen_server's init/1
immediately time out and then having a handle_info clause handle the timeout
so you can further initialize a gen_server, is not new -- it's a fairly well-
known hack (it's in _Erlang and OTP in Action_ [0] from 2010, for example).
But it is no longer considered a good idea, for reasons mentioned below. To
eliminate the need for this kind of hack, and its attendant issues, the new-
ish callback, handle_continue/2, was added to R21 back in 2018.

Here's a quick description of handle_continue/2 from the Erlang gen_server
docs [1]:

 _This function is called by a gen_server process whenever a previous callback
returns {continue, Continue}. handle_continue /2 is invoked immediately after
the previous callback, which makes it useful for performing work after
initialization or for splitting the work in a callback in multiple steps,
updating the process state along the way._

So, instead of init returning {ok, State, 0} you have init return: {continue,
Continue}. And you will have defined a handle_continue/2 clause whose first
parameter will match whatever is in the variable, Continue, and you do
whatever work you want done in that clause.

Now, as for why it's not a good idea to use the timeout zero hack, well, here
you go (these are Elixir references because that's what Google turned up for
me, but it all holds for Erlang as well):

From the Elixir GenServer docs[2]:

 _Because a message may arrive before the timeout is set, even a timeout of 0
milliseconds is not guaranteed to execute. To take another action immediately
and unconditionally, use a :continue instruction._

And, also, from a blog post about handle_continue [3]:

 _For the problems we looked at, an easier solution is to use the
handle_continue callback which was introduced in OTP 21, and guarantees that
the process will not accept any messages until the callback is finished. This
means that we can still have our asynchronous start up, without having to
worry about other messages being processed first._

So, if you want to create a gen_server and then have it do some further
initialization and you want this to all be atomic, use handle_continue/2\.
Otherwise, you run the risk of your new gen_server receiving messages before
you've finished that next stage of initialization.

[0] [https://livebook.manning.com/book/erlang-and-otp-in-
action/c...](https://livebook.manning.com/book/erlang-and-otp-in-
action/chapter-3/145)

[1]
[http://erlang.org/doc/man/gen_server.html#Module:handle_cont...](http://erlang.org/doc/man/gen_server.html#Module:handle_continue-2)

[2]
[https://hexdocs.pm/elixir/GenServer.html](https://hexdocs.pm/elixir/GenServer.html)

[3] [https://medium.com/@tylerpachal/introduction-to-handle-
conti...](https://medium.com/@tylerpachal/introduction-to-handle-continue-in-
elixir-and-when-to-use-it-53ba5519cc17)

