Packages
honeydew
1.2.5
1.5.0
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc7
1.0.0-rc6
1.0.0-rc5
1.0.0-rc4
1.0.0-rc3
1.0.0-rc2
1.0.0-rc1
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Pluggable local/clusterable job queue focused on safety.
Current section
Files
Jump to
Current section
Files
lib/honeydew/poll_queue.ex
defmodule Honeydew.PollQueue do
require Logger
alias Honeydew.Job
alias Honeydew.Queue
alias Honeydew.Queue.State, as: QueueState
@behaviour Queue
@type job :: Job.t()
@type private :: any()
@type name :: Honeydew.queue_name()
@type filter :: atom()
@callback init(name, arg :: any()) :: {:ok, private}
@callback reserve(private) :: {job, private}
@callback ack(job, private) :: private
@callback nack(job, private) :: private
@callback status(private) :: %{:count => number, :in_progress => number, optional(atom) => any}
@callback cancel(job, private) :: {:ok | {:error, :in_progress | :not_found}, private}
@callback filter(private, filter) :: [job]
@callback handle_info(msg :: :timeout | term, state :: private) ::
{:noreply, new_state}
| {:noreply, new_state, timeout | :hibernate}
| {:stop, reason :: term, new_state}
when new_state: private
defmodule State do
defstruct [:queue, :source, :poll_interval]
end
@impl true
def validate_args!(args) do
validate_poll_interval!(args[:poll_interval])
end
defp validate_poll_interval!(interval) when is_integer(interval) and interval > 0, do: :ok
defp validate_poll_interval!(nil), do: :ok
defp validate_poll_interval!(arg), do: raise ArgumentError, invalid_poll_interval_error(arg)
defp invalid_poll_interval_error(argument) do
"Poll interval must be positive integer number of seconds. You gave #{inspect argument}"
end
@impl true
def init(queue, [source, args]) do
poll_interval = args[:poll_interval] * 1_000 |> trunc
{:ok, source_state} = source.init(queue, args)
source = {source, source_state}
poll(poll_interval)
{:ok, %State{queue: queue, source: source, poll_interval: poll_interval}}
end
@impl true
def enqueue(job, state) do
nack(job, state)
{state, job}
end
@impl true
def reserve(%State{source: {source, source_state}} = state) do
case source.reserve(source_state) do
{:empty, source_state} ->
{:empty, %{state | source: {source, source_state}}}
{{:value, {id, job}}, source_state} ->
{%{job | private: id}, %{state | source: {source, source_state}}}
end
end
@impl true
def ack(job, %State{source: {source, source_state}} = state) do
%{state | source: {source, source.ack(job, source_state)}}
end
@impl true
def nack(job, %State{source: {source, source_state}} = state) do
%{state | source: {source, source.nack(job, source_state)}}
end
@impl true
def status(%State{source: {source, source_state}}) do
source.status(source_state)
end
@impl true
def filter(%State{source: {source, source_state}}, filter) when is_atom(filter) do
source.filter(source_state, filter)
end
@impl true
def filter(_state, _filter) do
raise "Implementations of PollQueue only support predefined filters (atoms)"
end
@impl true
def cancel(job, %State{source: {source, source_state}} = state) do
{response, source_state} = source.cancel(job, source_state)
{response, %{state | source: {source, source_state}}}
end
@impl true
def handle_info(:__poll__, %QueueState{private: %State{poll_interval: poll_interval}} = queue_state) do
poll(poll_interval)
{:noreply, Queue.dispatch(queue_state)}
end
@impl true
def handle_info(msg, %QueueState{private: %State{source: {source, _source_state}}} = queue_state) do
source.handle_info(msg, queue_state)
end
defp poll(poll_interval) do
{:ok, _} = :timer.send_after(poll_interval, :__poll__)
end
end