# DGen.Server

```elixir
Mix.install([
  {:dgen, path: "../dgen"},
  {:erlfdb, "~> 0.3"}
])
```

## Regular GenServer

A simple chat server that stores messages in memory.

```elixir
defmodule Message do
  defstruct [:id, :name, :text]
end

defmodule Chat do
  use GenServer

  defstruct idx: 0, messages: []

  def start(), do: GenServer.start(__MODULE__, [])

  def restart(pid) do
    GenServer.stop(pid)
    start()
  end

  def new_message(pid, name, text), do: GenServer.call(pid, {:new_message, name, text})

  def history(pid), do: GenServer.call(pid, :history)

  @impl true
  def init([]) do
    {:ok, %Chat{}}
  end

  @impl true
  def handle_call({:new_message, name, text}, _from, state=%Chat{}) do
    %{messages: messages, idx: idx} = state
    message = %Message{id: "#{idx+1}", name: name, text: text}
    resp_text = "Thanks for the message"
    response = %Message{id: "#{idx+2}", name: "system", text: resp_text}
    {:reply, resp_text, %{state | idx: idx+2, messages: messages ++ [message, response]}}
  end

  @impl true
  def handle_call(:history, _from, state=%Chat{}) do
    %{messages: messages} = state
    {:reply, messages, state}
  end
end
```

```elixir
{:ok, pid} = Chat.start()
```

Send a message and get a response.

```elixir
Chat.new_message(pid, "Alice", "Hello there")
```

```elixir
Chat.history(pid)
```

Now restart the server.

```elixir
{:ok, pid} = Chat.restart(pid)
```

**The history is lost** — regular GenServers don't persist state.

```elixir
Chat.history(pid)
```

## Durable GenServer

The same chat server, but using `DGen.Server` for automatic persistence.

```elixir
defmodule DChat do
  use DGen.Server

  defstruct idx: 0, messages: []

  def start(tenant), do: DGen.Server.start(__MODULE__, [], [tenant: tenant])

  def restart(pid, tenant) do
    GenServer.stop(pid)
    start(tenant)
  end

  def new_message(pid, name, text), do: DGen.Server.call(pid, {:new_message, name, text})

  def history(pid), do: DGen.Server.call(pid, :history)

  @impl true
  def init([]) do
    {:ok, %DChat{}}
  end

  @impl true
  def handle_call({:new_message, name, text}, _from, state=%DChat{}) do
    %{messages: messages, idx: idx} = state
    message = %Message{id: "#{idx+1}", name: name, text: text}
    resp_text = "Thanks for the message"
    response = %Message{id: "#{idx+2}", name: "system", text: resp_text}
    {:reply, resp_text, %{state | idx: idx+2, messages: messages ++ [message, response]}}
  end

  @impl true
  def handle_call(:history, _from, state=%DChat{}) do
    %{messages: messages} = state
    {:reply, messages, state}
  end
end
```

```elixir
b = :dgen_config.backend()
tenant = b.sandbox_open("DGen.Livebook", "Intro")
```

Create a tenant to isolate this server's data.

```elixir
{:ok, pid} = DChat.start(tenant)
```

```elixir
DChat.new_message(pid, "Bob", "Greetings")
```

```elixir
DChat.history(pid)
```

Restart the durable server.

```elixir
{:ok, pid} = DChat.restart(pid, tenant)
```

**The history persists** — DGen.Server automatically saves and restores state.

```elixir
DChat.history(pid)
```
