Current section
Files
Jump to
Current section
Files
lib/timers/serverless_workers.ex
defmodule Illithid.Timers.ServerlessWorkers do
# TODO(ian): Update when configurable
@moduledoc """
Kills worker processes who have no correlated running server
"""
use GenServer, restart: :transient
@api Application.get_env(:illithid, :digital_ocean)[:api_module]
alias Illithid.ServerManager.DigitalOcean.Supervisor
alias Illithid.ServerManager.Worker
require Logger
#######################
# GenServer Callbacks #
#######################
def start_link(_args) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_args) do
# TODO(ian): Magic number
Process.send_after(self(), :kill_orphans, 1000 * 5)
{:ok, %{}}
end
################
# Handle Calls #
################
def handle_info(:kill_orphans, state) do
for server <- find_serverless_workers(), do: kill_orphan(server)
{:noreply, state}
end
######################
# Internal Functions #
######################
@spec find_serverless_workers() :: [{pid, String.t()}]
defp find_serverless_workers do
case @api.list_servers() do
{:ok, servers} ->
server_names = Enum.map(servers, fn s -> s.name end)
pids_to_names =
Enum.map(Supervisor.children(), fn {_, child_pid, _, _} ->
{child_pid, Worker.get_server_name(child_pid)}
end)
retval =
Enum.filter(
pids_to_names,
fn {_pid, name} -> not Enum.member?(server_names, name) end
)
retval
_ ->
[]
end
end
@spec kill_orphan({pid, name :: String.t()}) :: :ok | {:error, atom()} | {:error, String.t()}
defp kill_orphan({pid, name}) do
Logger.info("Killing orphaned server #{name}")
case Supervisor.destroy_server(pid) do
{:ok, _} -> :ok
{:error, _} = retval -> retval
end
end
end