Packages

Background processing application/library written in Elixir that uses RabbitMQ as a messaging backend

Current section

Files

Jump to
carguero_task_bunny lib task_bunny status.ex
Raw

lib/task_bunny/status.ex

defmodule TaskBunny.Status do
@moduledoc false
# Functions that handle TaskBunny status.
#
# This module is private to TaskBunny.
# It's aimed at providing useful stats to Wobserver integration.
#
alias TaskBunny.{Status, Connection}
alias TaskBunny.Status.Worker
@typedoc ~S"""
The Worker status contains the follow fields:
- `version`, the current status version.
- `up`, whether the `TaskBunny.Supervisor` is running.
- `connected`, whether a connection to RabbitMQ has been made.
- `workers`, list of worker statuses.
"""
@type t :: %__MODULE__{
version: String.t(),
up: boolean,
connected: boolean,
workers: list(Worker.t())
}
defstruct version: "1", up: true, connected: false, workers: []
@doc ~S"""
Returns TaskBunny status.
"""
@spec overview(atom) :: Status.t()
def overview(supervisor \\ TaskBunny.Supervisor) do
case supervisor_alive?(supervisor) do
true ->
%Status{
up: true,
connected: get_connection_status(),
workers: get_workers_status(supervisor)
}
_ ->
%Status{
up: false,
connected: get_connection_status()
}
end
end
@doc ~S"""
Returns TaskBunny metrics.
"""
@spec metrics(atom) :: keyword
def metrics(supervisor \\ TaskBunny.Supervisor) do
case supervisor_alive?(supervisor) do
true ->
{runners, succeeded, failed, rejected} =
supervisor
|> get_workers_status()
|> Enum.reduce({[], [], [], []}, &get_worker_metrics/2)
[
task_bunny_job_runners_now: {runners, :gauge, "Current amount of TaskBunny runners."},
task_bunny_jobs_succeeded_total:
{succeeded, :counter, "The amount of succeeded TaskBunny jobs."},
task_bunny_jobs_failed_total:
{failed, :counter, "The amount of failed TaskBunny jobs."},
task_bunny_jobs_rejected_total:
{rejected, :counter, "The amount of rejected TaskBunny jobs."}
]
false ->
[]
end
end
@doc ~S"""
Returns TaskBunny `:wobserver` page.
"""
@spec page(atom) :: map
def page(supervisor \\ TaskBunny.Supervisor) do
page = %{
status: %{
running: supervisor_alive?(supervisor),
connected: get_connection_status()
}
}
case page.status.running do
true ->
page
|> Map.put_new(:workers, get_workers_page(supervisor))
false ->
page
end
end
@spec get_connection_status() :: boolean
defp get_connection_status do
case Connection.get_connection() do
{:ok, _} -> true
_ -> false
end
end
@spec supervisor_alive?(atom) :: boolean
defp supervisor_alive?(supervisor) do
case Process.whereis(supervisor) do
nil -> false
pid -> Process.alive?(pid)
end
end
@spec get_workers_status(atom) :: list(Worker.t())
defp get_workers_status(supervisor) do
supervisor
|> Supervisor.which_children()
|> Enum.map(&get_worker_supervisor_status/1)
|> List.flatten()
end
@spec get_workers_status({TaskBunny.WorkerSupervisor, pid, atom, list()}) :: list(Worker.t())
defp get_worker_supervisor_status({TaskBunny.WorkerSupervisor, pid, _atom, _list}) do
pid
|> Supervisor.which_children()
|> Enum.map(&Status.Worker.get/1)
end
@spec get_worker_supervisor_status(any) :: []
defp get_worker_supervisor_status(_) do
[]
end
@spec get_workers_page(atom) :: list(map)
defp get_workers_page(supervisor) do
supervisor
|> get_workers_status()
|> Enum.map(fn worker ->
%{
queue: worker.queue,
runners: worker.runners,
channel: worker.channel,
succeeded: worker.stats.succeeded,
failed: worker.stats.failed,
rejected: worker.stats.rejected
}
end)
end
@spec get_worker_metrics(Worker.t(), {list, list, list, list}) :: {list, list, list, list}
defp get_worker_metrics(worker, {runners, succeeded, failed, rejected}) do
{
[{worker.runners, [queue: worker.queue]} | runners],
[{worker.stats.succeeded, [queue: worker.queue]} | succeeded],
[{worker.stats.failed, [queue: worker.queue]} | failed],
[{worker.stats.rejected, [queue: worker.queue]} | rejected]
}
end
end