defmodule MyApp.RedisServer do
use Task, restart: :permanent
def start_link([]) do
Task.start_link(__MODULE__, :run, [])
end
@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)
end
end
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?
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.