defmodule Oban.Met.Application do @moduledoc false use Application alias Oban.{Config, Registry} require Logger @main_sup Oban.Met.Supervisor @task_sup Oban.Met.TaskSupervisor @handler_id :oban_met_handler @impl Application def start(_type, _args) do :telemetry.attach(@handler_id, [:oban, :supervisor, :init], &__MODULE__.init_metrics/4, []) children = [ {Task.Supervisor, name: @task_sup}, {Task, &boot_metrics/0} ] Supervisor.start_link(children, strategy: :one_for_one, name: @main_sup) end @impl Application def prep_stop(state) do :telemetry.detach(@handler_id) state end @doc false def init_metrics(_event, _measure, %{conf: conf}, _conf) do start_metrics(conf) end @doc false def boot_metrics do guard = {:andalso, {:is_map, :"$1"}, {:==, {:map_get, :__struct__, :"$1"}, Config}} [{{:_, :_, :"$1"}, [guard], [:"$1"]}] |> Registry.select() |> Enum.each(&start_metrics/1) end defp start_metrics(conf) do opts = Application.get_all_env(:oban_met) if opts[:auto_start] and conf.testing in opts[:auto_testing_modes] do spec = Oban.Met.child_spec(conf: conf) case Supervisor.start_child(@main_sup, spec) do {:ok, _pid} -> Task.Supervisor.start_child(@task_sup, fn -> watch_oban(spec, conf) end) :ok {:error, {:already_started, _pid}} -> :ok {:error, {error, _stack}} -> Logger.error("Unable to start Oban.Met supervisor: #{inspect(error)}") end end end defp watch_oban(%{id: child_id}, conf) do ref = conf.name |> Oban.whereis() |> Process.monitor() receive do {:DOWN, ^ref, :process, _pid, _reason} -> Process.demonitor(ref, [:flush]) with :ok <- Supervisor.terminate_child(@main_sup, child_id) do Supervisor.delete_child(@main_sup, child_id) end end end end