View Source Nebulex.Hook (Nebulex v2.6.4)
Pre/Post Hooks
Since v2.0.0
, pre/post hooks are not supported and/or handled by Nebulex
itself. Hooks feature is not a common use-case and also it is something that
can be be easily implemented on top of the Cache at the application level.
Nevertheless, to keep backward compatibility somehow, Nebulex
provides the
next decorators for implementing pre/post hooks very easily.
before
decorator
The before
decorator is declared for performing a hook action or callback
before the annotated function is executed.
@decorate before(fn %Nebulex.Hook{} = hook -> inspect(hook) end)
def some_fun(var) do
# logic ...
end
after_return
decorator
The after_return
decorator is declared for performing a hook action or
callback after the annotated function is executed and its return is passed
through the return:
attribute.
@decorate after_return(&inspect(&1.return))
def some_fun(var) do
# logic ...
end
around
decorator
The final kind of hook is around
decorator. The around
decorator runs
"around" the annotated function execution. It has the opportunity to do
work both before and after the function executes. This means the
given hook function is invoked twice, before and after the code-block is
evaluated.
@decorate around(&inspect(&1.step))
def some_fun(var) do
# logic ...
end
Putting all together
Suppose we want to track all cache calls (before and after they are called) by logging them (including the execution time). In this case, we need to provide a pre/post hook to log these calls.
First of all, we have to create a module implementing the hook function:
defmodule MyApp.Tracker do
use GenServer
alias Nebulex.Hook
require Logger
@actions [:get, :put]
## API
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end
def track(%Hook{step: :before, name: name}) when name in @actions do
System.system_time(:microsecond)
end
def track(%Hook{step: :after_return, name: name} = event) when name in @actions do
GenServer.cast(__MODULE__, {:track, event})
end
def track(hook), do: hook
## GenServer Callbacks
@impl true
def init(_opts) do
{:ok, %{}}
end
@impl true
def handle_cast({:track, %Hook{acc: start} = hook}, state) do
diff = System.system_time(:microsecond) - start
Logger.info("#=> #{hook.module}.#{hook.name}/#{hook.arity}, Duration: #{diff}")
{:noreply, state}
end
end
And then, in the Cache:
defmodule MyApp.Cache do
use Nebulex.Hook
@decorate_all around(&MyApp.Tracker.track/1)
use Nebulex.Cache,
otp_app: :my_app,
adapter: Nebulex.Adapters.Local
end
Try it out:
iex> MyApp.Cache.put 1, 1
10:19:47.736 [info] Elixir.MyApp.Cache.put/3, Duration: 27
iex> MyApp.Cache.get 1
10:20:14.941 [info] Elixir.MyApp.Cache.get/2, Duration: 11
Summary
Functions
After-return decorator.
Around decorator.
Before decorator.
This function is for internal purposes.
Types
@type t() :: %Nebulex.Hook{ acc: term(), arity: non_neg_integer(), module: Nebulex.Cache.t(), name: atom(), return: term(), step: :before | :after_return }
Functions
After-return decorator.
Intercepts any call to the annotated function and calls the given fun
after the logic is executed, and the returned result is passed through
the return:
attribute.
Example
defmodule MyApp.Example do
use Nebulex.Hook
@decorate after_return(&inspect(&1))
def some_fun(var) do
# logic ...
end
end
Around decorator.
Intercepts any call to the annotated function and calls the given fun
before and after the logic is executed. The result of the first call to
the hook function is passed through the acc:
attribute, so it can be
used in the next call (after return). Finally, as the after_return
decorator, the returned code-block evaluation is passed through the
return:
attribute.
Example
defmodule MyApp.Profiling do
alias Nebulex.Hook
def prof(%Hook{step: :before}) do
System.system_time(:microsecond)
end
def prof(%Hook{step: :after_return, acc: start} = hook) do
:telemetry.execute(
[:my_app, :profiling],
%{duration: System.system_time(:microsecond) - start},
%{module: hook.module, name: hook.name}
)
end
end
defmodule MyApp.Example do
use Nebulex.Hook
@decorate around(&MyApp.Profiling.prof/1)
def some_fun(var) do
# logic ...
end
end
Before decorator.
Intercepts any call to the annotated function and calls the given fun
before the logic is executed.
Example
defmodule MyApp.Example do
use Nebulex.Hook
@decorate before(&inspect(&1))
def some_fun(var) do
# logic ...
end
end
This function is for internal purposes.