# Peeper
**Almost drop-in replacement for `GenServer` to preserve state between crashes.**
## Benefits
`Peeper.GenServer` is an almost drop-in replacement for `GenServer` that preserves the state
between crashes. All the callbacks from `GenServer` are supported.
Internally it creates a sub-supervision tree with an actual worker that delegates to the
implementation and a state keeper. That said, it creates three processes instead of one,
and this should be considered when building a very concurrent applications.
The main use-case would be a long-lived `GenServer` process with no error path handling at all
(yeah, that famous _Let It Crash_.) Using this abstraction, one is free to send unexpected
messages to the process, raise from its `handle_×××` clauses and whatnot.
There are two differencies compared to bare `GenServer`. `init/1` callback cannot return anything
but `{:ok, state}` tuple (this might have changed in the future,) and
`Peeper.{call/3,cast/2,send/2}` is to be used instead of `GenServer.{call/3,cast/2}` and
`Kernel.send/2` (this is not gonna change.)
Please note, that whatever is set in `init/1` callback as a state, will be overriden by
the latest state available upon restarts. That being said, `init/1` would play its role
in setting the state during the first run only.
Instead of using `Peeper`’s counterparts, one might either name the process and use `Name.GenServer`
as a name of the underlying `GenServer` or get the `GenServer`’s `pid` via `Peeper.gen_server/1`
and use `GenServer.{call/3,cast/2}` with it.
### Example
```elixir
iex> {:ok, pid} = Peeper.Impls.Full.start_link(state: 0, name: Counter)
...> Peeper.call(pid, :state)
0
iex> Peeper.cast(pid, :inc)
:ok
iex> GenServer.call(Counter.GenServer, :state)
1
iex> Peeper.call(pid, :state)
1
iex> # emulate crash
...> Process.exit(Peeper.Supervisor.worker(pid), :raise)
...> %{} = Peeper.Supervisor.which_children(pid)
iex> Peeper.call(Counter, :state)
1
iex> Peeper.send(pid, :inc)
:inc
iex> Peeper.call(Counter, :state)
2
```
### `start_link/1`
The function receives either an initial `state`, or a keyword having keys
`state` and (optionally) `name`. Also this keyword might have a configuration
for the top supervisor (keys: `[:strategy, :max_restarts, :max_seconds, :auto_shutdown]`.)
All other values passed would be re-passed to the underlying `GenServer`’s options.
### Listener
One might pass `listener: MyListener` key to `PeeperImpl.start_link/1` where `MyListener`
should be an implementation of `Peeper.Listener` behaviour. The callbacks will be called
when the state of the underlying behaviour is _changed_ and on termination respectively.
That might be a good place to attach telemetry events, or logs, or whatnot.
## Usage
### Installation
```elixir
def deps do
[
{:peeper, "~> 0.1"}
]
end
```
### [Documentation](https://hexdocs.pm/peeper)