Packages
verk
1.5.0
1.7.3
1.7.2
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.0
1.4.1
1.4.0
1.3.0
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.2
1.0.1
1.0.0
0.14.1
0.14.0
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.0
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
Verk is a job processing system backed by Redis.
Current section
Files
Jump to
Current section
Files
lib/verk/queue_stats.ex
defmodule Verk.QueueStats do
@moduledoc """
This process will update an :ets table with the following information per queue
* Current amount of running jobs
* Amount of finished jobs
* Amount of failed jobs
It will persist to redis from time to time
It also holds information about the current status of queus. They can be:
* running
* idle
* pausing
* paused
"""
use GenStage
require Logger
alias Verk.QueueStatsCounters
defmodule State do
@moduledoc false
defstruct queues: %{}
end
@persist_interval 10_000
@doc false
def start_link() do
GenStage.start_link(__MODULE__, :ok, name: __MODULE__)
end
@doc """
Lists the queues and their stats searching for a `prefix` if provided
"""
@spec all(binary) :: Map.t()
def all(prefix \\ "") do
GenServer.call(__MODULE__, {:all, prefix})
end
defp status(queue, queues, running_counter) do
status = queues[queue] || Verk.Manager.status(queue)
if status == :running and running_counter == 0 do
:idle
else
status
end
end
@doc false
def init(_) do
QueueStatsCounters.init()
Process.send_after(self(), :persist_stats, @persist_interval)
{:consumer, %State{}, subscribe_to: [Verk.EventProducer]}
end
def handle_call({:all, prefix}, _from, state) do
result =
for {queue, running, finished, failed} <- QueueStatsCounters.all(prefix), is_list(queue) do
queue = to_string(queue)
%{
queue: queue,
status: status(queue, state.queues, running),
running_counter: running,
finished_counter: finished,
failed_counter: failed
}
end
queues =
for %{queue: queue, status: status} <- result, into: state.queues, do: {queue, status}
{:reply, result, [], %State{queues: queues}}
end
def handle_events(events, _from, state) do
new_state =
Enum.reduce(events, state, fn event, state ->
handle_event(event, state)
end)
{:noreply, [], new_state}
end
@doc false
defp handle_event(%Verk.Events.JobStarted{job: job}, state) do
QueueStatsCounters.register(:started, job.queue)
state
end
defp handle_event(%Verk.Events.JobFinished{job: job}, state) do
QueueStatsCounters.register(:finished, job.queue)
state
end
defp handle_event(%Verk.Events.JobFailed{job: job}, state) do
QueueStatsCounters.register(:failed, job.queue)
state
end
defp handle_event(%Verk.Events.QueueRunning{queue: queue}, state) do
QueueStatsCounters.reset_started(queue)
%{state | queues: Map.put(state.queues, to_string(queue), :running)}
end
defp handle_event(%Verk.Events.QueuePausing{queue: queue}, state) do
%{state | queues: Map.put(state.queues, to_string(queue), :pausing)}
end
defp handle_event(%Verk.Events.QueuePaused{queue: queue}, state) do
%{state | queues: Map.put(state.queues, to_string(queue), :paused)}
end
@doc false
def handle_info(:persist_stats, state) do
case QueueStatsCounters.persist() do
:ok ->
:ok
{:error, reason} ->
Logger.error("QueueStats failed to persist stats to Redis. Reason: #{inspect(reason)}")
end
Process.send_after(self(), :persist_stats, @persist_interval)
{:noreply, [], state}
end
@doc false
def handle_info(_, state) do
{:noreply, [], state}
end
end