When you spawn and link a process inside a Task, it doesn’t seem to die when the Task ends.
defmodule Foo do
use GenServer
def start_link(), do: GenServer.start_link(__MODULE__, nil)
def init(nil), do: {:ok, nil}
end
iex> {:ok, pid} = Task.async(fn -> Foo.start_link() end) |> Task.await()
iex> Process.alive?(pid)
true
I thought the GenServer process would be linked to the Task and thus end when the Task ends.
Now that I’m saying this out loud, I’m thinking it’s because the Task ends normally, which then doesn’t bring down linked processes?
Is there a way to do this though?
Use case is people are spawning network connection type GenServers inside web requests and background jobs and not shutting them down, so they leak. It would be nice if the connections automatically stopped when the process they are linked to stopped.
So the only thing I can think of is using some kind of connection manager which monitors the calling process and then automatically cleans up any connections if the calling process ends.
# in application.ex
children = [RedixConnectionManager]
# in web controller/action, background job, etc.
{:ok, pid} = RedixConnectionManager.new_connection()
results = Redix.command!(pid, ["keys", "*"])
Is that too heavy handed or seems about right?
P.S. The Redis connection example is contrived; we use NimblePool around Redix connections so it’s a total non-issue.
The GenServer does not die because the task ends with a normal exit (no error). If you call exit(:my_error) from the task, or raise something, the GenServer will be killed too.