Skip to content

Instantly share code, notes, and snippets.

@joladev
Created February 7, 2020 10:10
Show Gist options
  • Save joladev/a6fb31b0fb63cac246a333e5c22a3f4d to your computer and use it in GitHub Desktop.
Save joladev/a6fb31b0fb63cac246a333e5c22a3f4d to your computer and use it in GitHub Desktop.
Example of keeping ETS tables alive through process failures
defmodule Manager do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(_) do
Process.flag(:trap_exit, true)
worker = Process.whereis(Worker)
Process.link(worker)
table = :ets.new(:give_away, [:private])
data = {:count, 0}
:ets.insert(table, data)
:ets.setopts(table, {:heir, self(), data})
:ets.give_away(table, worker, data)
{:ok, table}
end
def handle_info({:EXIT, _from, _reason}, table), do: {:noreply, table}
def handle_info({:"ETS-TRANSFER", table, _pid, data}, _table) do
worker = wait_for_worker()
Process.link(worker)
:ets.give_away(table, worker, data)
{:noreply, table}
end
def wait_for_worker() do
case Process.whereis(Worker) do
nil ->
Process.sleep(1)
wait_for_worker()
pid -> pid
end
end
end
defmodule Worker do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(_) do
{:ok, nil}
end
def handle_info({:"ETS-TRANSFER", table, _pid, _data}, _table) do
{:noreply, table}
end
def handle_call({:get, key}, _from, table) do
case :ets.lookup(table, key) do
[] ->
{:reply, nil, table}
[{_key, value}] ->
{:reply, value, table}
end
end
def handle_call({:put, key, value}, _from, table) do
result = :ets.insert(table, {key, value})
{:reply, result, table}
end
def handle_cast(:die, table) do
{:stop, table, :killed}
end
def get(key) do
GenServer.call(__MODULE__, {:get, key})
end
def put(key, value) do
GenServer.call(__MODULE__, {:put, key, value})
end
def die() do
GenServer.cast(__MODULE__, :die)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment