Last active
August 29, 2015 14:04
-
-
Save fishcakez/bd2be0f2174a091acda1 to your computer and use it in GitHub Desktop.
EnterLoop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule EnterLoop do | |
use GenServer | |
require Logger | |
def start_link(opts) do | |
spawn_opts = Keyword.get(opts, :spawn_opt, []) | |
# :infinity start timeout | |
:proc_lib.start_link(__MODULE__, :init_it, [opts], :infinity, spawn_opts) | |
end | |
def init_it(opts) do | |
register() | |
try do | |
# do some init | |
:ok | |
# send ackowledgement to starter | |
:proc_lib.init_ack({:ok, self()}) | |
else | |
:ok -> | |
# do more init | |
post_ack() | |
catch | |
# include stacktrace in exit reason on error | |
:error, value -> | |
init_stop({value, System.stacktrace()}) | |
:throw, value -> | |
init_stop({{:nocatch, value}, System.stacktrace()}) | |
:exit, value -> | |
init_stop(value) | |
end | |
end | |
defp register() do | |
try do | |
Process.register(self(), __MODULE__) | |
rescue | |
ArgumentError -> | |
pid = Process.whereis(__MODULE__) || :undefined | |
reason = {:error, {:already_started, pid}} | |
:proc_lib.init_ack(reason) | |
exit(:normal) | |
end | |
end | |
defp post_ack() do | |
try do | |
# do more init | |
:ok | |
else | |
:ok -> | |
# nil state, :infinity timeout. | |
:gen_server.enter_loop(__MODULE__, opts, nil, {:local, __MODULE__}, | |
:infinity) | |
catch | |
# include stacktrace in exit reason on error | |
:error, value -> | |
stop({value, System.stacktrace()}) | |
:throw, value -> | |
stop({{:nocatch, value}, System.stacktrace()}) | |
:exit, value -> | |
stop(value) | |
end | |
end | |
defp init_stop(reason) do | |
# no need to log here because reason passed to starter | |
# unregister first before sending ack so that not still registered if | |
# supervisor tries again. This may only be required for :global or :via | |
Process.unregister(__MODULE__) | |
# send error acknowledgement | |
:proc_lib.init_ack({:error, reason}) | |
exit(reason) | |
end | |
defp stop(reason) do | |
# might want to log error | |
Logger.error("Failed to init #{__MODULE__}\n" <> | |
Exception.format_exit(reason)) | |
exit(reason) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment