Zombie processes - how to stop the unix process started by System.cmd when the Elixir app stops?

I want my Elixir app to managed a Unix process…

defmodule MyApp.RedisServer do
  use Task, restart: :permanent

  def start_link([]) do
    Task.start_link(__MODULE__, :run, [])

  @args ~w(--unixsocket redis.sock --port 0)
  @options [stderr_to_stdout: true, into: IO.stream(:stdio, :line)]

  def run do
    System.cmd("redis-server", @args, @options)

Then I shove that task into my app’s supervision tree. The problem is that if I ctrl-c ctrl-c the Elixir app, then the redis-server Unix process is still running.

How to stop the unix process started by System.cmd when the Elixir app stops?

Thanks for the help!

trap exit and when you see a :EXIT message kill the process.


I am not sure what you want to achieve, running a long running external process through System.cmd does not seem right. You can use a port at least, or something even fancier.

I just want a Unix process started up when the Elixir app starts up and killed when the Elixir app terminates. The Unix process isn’t a daemon; it runs in the foreground.

Further, if the Unix process dies while the Elixir app is running, I want it restarted; hence the supervised Task.


It is not as simple as it look. To kill a external process, you have to maximize the chance it naturally quits, so your data is not corrupted. Also you may want to capture its output as log, and if it crash, you want to have some progressive push back in restart, or you can end up with very ugly situation.

This is why people use external daemon watchers. General speaking your application should tolerate dependency service being off-line and reconnect when it is back up. Trying to do more than that is usually not the best idea.

The Port documentation addresses this problem.


In my build utility package I wrote a wrapper Elixir script to kill a child process when the parent’s STDIN closes: lib/apprunner.exs · master · Mikko Ahlroth / mbu · GitLab