zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

watcher.ex (1864B)


      1 defmodule DBConnection.Watcher do
      2   @moduledoc false
      3   @name __MODULE__
      4 
      5   use GenServer
      6 
      7   def start_link(_) do
      8     GenServer.start_link(__MODULE__, :ok, name: @name)
      9   end
     10 
     11   def watch(supervisor, args) do
     12     GenServer.call(@name, {:watch, supervisor, args}, :infinity)
     13   end
     14 
     15   def init(:ok) do
     16     Process.flag(:trap_exit, true)
     17     {:ok, {%{}, %{}}}
     18   end
     19 
     20   def handle_call({:watch, supervisor, args}, {caller_pid, _ref}, {caller_refs, started_refs}) do
     21     case DynamicSupervisor.start_child(supervisor, args) do
     22       {:ok, started_pid} ->
     23         Process.link(caller_pid)
     24         caller_ref = Process.monitor(caller_pid)
     25         started_ref = Process.monitor(started_pid)
     26         caller_refs = Map.put(caller_refs, caller_ref, {supervisor, started_pid, started_ref})
     27         started_refs = Map.put(started_refs, started_ref, {caller_pid, caller_ref})
     28         {:reply, {:ok, started_pid}, {caller_refs, started_refs}}
     29 
     30       other ->
     31         {:reply, other, {caller_refs, started_refs}}
     32     end
     33   end
     34 
     35   def handle_info({:DOWN, ref, _, _, _}, {caller_refs, started_refs}) do
     36     case caller_refs do
     37       %{^ref => {supervisor, started_pid, started_ref}} ->
     38         Process.demonitor(started_ref, [:flush])
     39         DynamicSupervisor.terminate_child(supervisor, started_pid)
     40         {:noreply, {Map.delete(caller_refs, ref), Map.delete(started_refs, started_ref)}}
     41 
     42       %{} ->
     43         %{^ref => {caller_pid, caller_ref}} = started_refs
     44         Process.demonitor(caller_ref, [:flush])
     45         Process.exit(caller_pid, :kill)
     46         {:noreply, {Map.delete(caller_refs, caller_ref), Map.delete(started_refs, ref)}}
     47     end
     48   end
     49 
     50   def handle_info({:EXIT, _, _}, state) do
     51     {:noreply, state}
     52   end
     53 
     54   def terminate(_, {_, started_refs}) do
     55     for {_, {caller_pid, _}} <- started_refs do
     56       Process.exit(caller_pid, :kill)
     57     end
     58 
     59     :ok
     60   end
     61 end