Current section

Files

Jump to
combo lib combo endpoint sync_code_reload_plug.ex
Raw

lib/combo/endpoint/sync_code_reload_plug.ex

defmodule Combo.Endpoint.SyncCodeReloadPlug do
@moduledoc """
Wraps an endpoint, attempting to sync with `Combo.CodeReloader` if an
exception is raised which indicates that we may be in the middle of a reload.
We detect this by looking at the raised exception and seeing if it indicates
that the endpoint is not defined. This indicates that the code reloader may be
midway through a compile, and that we should attempt to retry the request
after the compile has completed. This is also why this must be implemented in
a separate module (one that is not recompiled in a typical code reload cycle),
since otherwise it may be the case that the endpoint itself is not defined.
"""
@behaviour Plug
def init({endpoint, opts}), do: {endpoint, endpoint.init(opts)}
def call(conn, {endpoint, opts}), do: do_call(conn, endpoint, opts, true)
defp do_call(conn, endpoint, opts, retry?) do
try do
endpoint.call(conn, opts)
rescue
exception in [UndefinedFunctionError] ->
case exception do
%UndefinedFunctionError{module: ^endpoint} when retry? ->
# Sync with the code reloader and retry once
Combo.CodeReloader.sync()
do_call(conn, endpoint, opts, false)
exception ->
reraise(exception, __STACKTRACE__)
end
end
end
end