How to kill drab commander processes

Following from this question, how do I actually shut down a process in drab?

Looking at the drab implementation I cant really figure out how to shutdown the process in a clean way. I am running a separate process when I start that holds the pid of the process I want to kill and then I have tried all manner of things like below but the result is always a crash and error log.

Process.exit(pid, :killed)

Sorry, I believe I don’t completely understood the question.

By the “drab commander process” you mean the process which runs when you run the event handler function in the commander?
If this is it, you don’t have to do anything. Process will stop when the function ends.

If you mean any other process you start in the event handler, well, you need to take care about it yourself. Just be away, that if you start the process linked with handler process, killing it will kill the handler as well, which causes with an error (see https://tg.pl/drab#errors).

Can you show a few lines of code of how you’re starting and killing your process? And the errors you’ve talked about in error log.

1 Like

Sorry im unclear, my commander runs an infinit process like this.

defmodule BfgWebWeb.PageCommander do
  use Drab.Commander
  require Hub
  require Logger

  defhandler subscribe_market(socket, _sender, market_id) do
    Logger.debug("Change subscription to #{market_id} is it string #{is_binary(market_id)}")
    sub = Hub.subscribe(market_id, _)
    :ok = BfgWebWeb.Manager.set_running(pid: self(), sub: sub)
    handle_event(socket)
  end

  defp handle_event(socket) do
    receive do
      msg  ->
        Logger.warn("Got msg #{inspect msg}")
      {:ok, events} = Drab.Live.peek(socket, :genevent)
      socket
      |> poke(genevent: inspect(msg) <> "\n" <> events)
    end
    handle_event(socket)
  end
end

Its the job of the manager to handle killing to process.

defmodule BfgWebWeb.Manager do
  use GenServer
  require Logger

  @me __MODULE__
  @initial_state %{sub: nil, pid: nil}

  def set_running(pid: pid, sub: sub) do
    GenServer.call(@me, {:running_process, pid, sub})
  end

  def get_state() do
    GenServer.call(@me, :get_state)
  end

  def handle_call(:get_state, _from, %{pid: pid} = state) do
    {:reply, pid, state}
  end

  def handle_call({:running_process, pid, sub}, _from, %{sub: old_sub} = state) do
    if old_sub && pid do
      Hub.unsubscribe(old_sub)
      Process.exit(pid, :killed)
    end
    {:reply, :ok, %{state | sub: sub, pid: pid}}
  end

  def start_link(_) do
    GenServer.start_link(@me, nil, name: @me)
  end

  def init(_) do
    {:ok, @initial_state}
  end

end

This is not a very good implementation but it should work as a first prototype if I only can kill the process.

It looks like you want to keep the event handler process in the infinite loop. I believe something (this Hub?) sends a message to your event handler process? In this case you want to check :genevent, and then poke inspect(msg) <> "\n" <> events again to :genevent assign? I understand you are keeping this in the assign because the other process in the same page can modify it in the meantime?

Why are you getting errors in the log? probably because of BfgWebWeb.Manager.set_running(pid: self(), sub: sub), which may kill the event handler process (depending of what Hub.subscribe returns).

Why not, instead of killing, send a gentle message to the process? in handle_event:

receive do
  :please_finish -> :not_a_problem_sir
  msg -> ...
    handle_event(socket)
end

And in the genserver, instead of killing the process, send him a gentle goodbye message:

    if old_sub && pid do
      Hub.unsubscribe(old_sub)
      send(pid, :please_finish)
    end

But still, it looks a little bit overcomplicated :slight_smile: Maybe it is a X/Y problem and if you explain what you do want to archive, we could have a more suitable solution.

2 Likes

Hmm thanks this looks much better.
If you look at this you can see when you helped me with the first part of this problem.

Basically what I want is to have a monitor system using drab and to be able to switch what server events I want to subscribe on. The user should be able to click a button in the gui and a new subscription is done that generates events. I have based my solution on the demo example you have the only difference is that I want to be able to change for example what log file it is that we are listening on (given your example with log files)

So you are doing it right, I suppose, at least I don’t see the better solution right now. Just instead of killing, gently exit the process and you’ll be done.

1 Like