Peeper
is a library, that allows to preserve state between process crashes (including ETS and process dictionary,) as well as moving processes across dynamic supervisors (including a distributed transfer across nodes.)
It keeps both process dictionary and private ETS private. The caveat is all the incoming async messages during a process transfer are to be lost and the huge ETS would have been copied across nodes, which might be not an option.
Excerpt from tests:
{:ok, source_pid} = DynamicSupervisor.start_link(name: SDS)
{:ok, pid} = DynamicSupervisor.start_child(SDS, {MyProcess, state: 0, name: P})
assert 0 == Peeper.call(P, :state)
# creates a private ETS with ‹CONTENT›
assert :ok == Peeper.cast(pid, {:create_ets, :my_ets})
# amends process dictionary
assert :ok == Peeper.cast(pid, {:set_pd, :foo, 42})
# amends process state
assert :ok == Peeper.cast(pid, :inc)
assert 1 == Peeper.call(P3, :state)
Process.exit(Peeper.Supervisor.worker(pid), :kill)
assert 1 == Peeper.call(P, :state)
assert 42 == Peeper.call(P, {:get_pd, :foo})
assert ‹ETS CONTENT› = Peeper.call(P, {:ets, :my_ets})
{:ok, target_pid} = DynamicSupervisor.start_link(name: TDS)
Peeper.transfer(P3, source_pid, target_pid)
assert [{:undefined, pid, :supervisor, _}] = DynamicSupervisor.which_children(TDS)
assert pid == GenServer.whereis(P)
assert 1 == Peeper.call(P, :state)
assert 42 == Peeper.call(P, {:get_pd, :foo})
assert ‹ETS CONTENT› = Peeper.call(P, {:ets, :my_ets})