Skip to content

Instantly share code, notes, and snippets.

@santosh79
Last active May 31, 2016 09:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save santosh79/0018d228275da64679bc616d126245e4 to your computer and use it in GitHub Desktop.
Save santosh79/0018d228275da64679bc616d126245e4 to your computer and use it in GitHub Desktop.
defmodule MigratingProcesses.Manager do
use GenServer
def start_link do
GenServer.start_link __MODULE__, :ok, [name: :migration_manager]
end
def init(:ok) do
Process.flag :trap_exit, true
{:ok, %{}}
end
def start_worker(name) do
GenServer.call :migration_manager, {:start_worker, name}
end
def get_worker(worker_name) do
GenServer.call :migration_manager, {:get_worker, worker_name}
end
def clone_worker(old_worker_name) do
GenServer.call :migration_manager, {:clone_worker, old_worker_name}
end
def handle_cast({:change_state, old_worker_name, new_pid}, state) do
new_state = Dict.put(state, old_worker_name, new_pid)
{:noreply, new_state}
end
def handle_call({:clone_worker, old_worker_name}, _from, state) do
old_worker_pid = Dict.get old_worker_name
new_pid = MigratingProcesses.Worker.clone old_worker_pid
Process.link new_pid
master = self
spawn(fn ->
CHANGE_TIME = 5_000
:timer.sleep CHANGE_TIME
GenServer.cast master, {:change_state, old_worker_name, new_pid}
end)
spawn(fn ->
CATCHUP_TIME = 10_000
:timer.sleep CATCHUP_TIME
GenServer.stop old_worker_pid
end)
{:reply, :ok, new_state}
end
def handle_call({:get_worker, worker_name}, _from, state) do
worker = Dict.get(state, worker_name}
{:reply, worker, state}
end
def handle_call({:start_worker, name}, _from, state) do
{:ok, worker} = MigratingProcesses.Worker.start_link name
new_state = Dict.put(state, name, worker)
{:reply, :ok, new_state}
end
end
defmodule MigratingProcesses.Worker do
use GenServer
def start_link(name) do
GenServer.start_link __MODULE__, {:ok, name}, []
end
def start(name) do
GenServer.start __MODULE__, {:ok, name}, []
end
def start(_name, state) do
GenServer.start __MODULE__, {:ok, :state, state}, []
end
def init({:ok, name}) do
{:ok, %{name: name}}
end
def init({:ok, :state, state}) do
{:ok, state}
end
def clone(pid) do
GenServer.call pid, :clone
end
def set(pid, val) do
GenServer.call pid, {:set, val}
end
def get(pid, val) do
GenServer.call pid, :get
end
def handle_call(args, _from, %{stale: true, new_pid: new_pid} = state) do
GenServer.call new_pid, args
end
def handle_call(:clone, _from, state) do
{:ok, pid} = MigratingProcesses.Worker.start name, state
new_state = Dict.merge(state, %{stale: true, new_pid: pid})
{:reply, pid, new_state}
end
def handle_call(:get, _from, %{val: val} = state) do
{:reply, val, state}
end
def handle_call({:set, val}, _from, state) do
new_state = Dict.put(state, :val, val)
{:reply, :ok, new_state}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment