Current section
Files
Jump to
Current section
Files
lib/task_bunny/config.ex
defmodule TaskBunny.Config do
@moduledoc """
Handles TaskBunny configuration.
"""
alias TaskBunny.ConfigError
@default_concurrency 2
@doc """
Returns list of hosts.
"""
@spec hosts :: [atom]
def hosts do
hosts_config()
|> Enum.map(fn {host, _options} -> host end)
end
@doc """
Returns configuration for the host.
## Examples
iex> host_config(:default)
[connection_options: "amqp://localhost?heartbeat=30"]
"""
@spec host_config(atom) :: keyword | nil
def host_config(host) do
hosts_config()[host]
end
@doc """
Returns connect options for the host.
"""
@spec connect_options(host :: atom) :: list | String.t()
def connect_options(host) do
hosts_config()[host][:connect_options] ||
raise ConfigError, message: "Can not find host '#{host}' in config"
end
@doc """
Returns list of queues.
"""
@spec queues :: [keyword]
def queues do
:task_bunny
|> Application.get_all_env()
|> Enum.filter(fn {key, _} ->
is_atom(key) && Atom.to_string(key) =~ ~r/queue$/
end)
|> Enum.map(fn {_, queue_config} -> parse_queue_config(queue_config) end)
|> Enum.flat_map(fn queue_list -> queue_list end)
end
# Get queue config and returns list of queues with namespace
defp parse_queue_config(queue_config) do
namespace = queue_config[:namespace] || ""
queue_config[:queues]
|> Enum.map(fn queue ->
unless queue[:name] do
raise ConfigError, message: "name is missing in queue definition. #{inspect(queue)}"
end
Keyword.merge(queue, name: namespace <> queue[:name])
end)
end
@doc """
Transforms queue configuration into list of workers for the application to run.
"""
@spec workers :: [keyword]
def workers do
queues()
|> Enum.filter(&worker_enabled?/1)
|> Enum.map(fn queue ->
concurrency =
if queue[:worker] && queue[:worker][:concurrency] do
queue[:worker][:concurrency]
else
@default_concurrency
end
store_rejected_jobs =
if queue[:worker] && is_boolean(queue[:worker][:store_rejected_jobs]) do
queue[:worker][:store_rejected_jobs]
else
true
end
[
queue: queue[:name],
concurrency: concurrency,
store_rejected_jobs: store_rejected_jobs,
host: queue[:host] || :default
]
end)
end
# Checks worker configuration sanity.
@spec worker_enabled?(keyword) :: boolean
defp worker_enabled?(queue) do
case Keyword.get(queue, :worker, []) do
false ->
false
worker ->
concurrency = Keyword.get(worker, :concurrency, @default_concurrency)
concurrency > 0
end
end
@doc """
Returns a queue for the given job.
"""
@spec queue_for_job(atom) :: keyword | nil
def queue_for_job(job) do
Enum.find(queues(), fn queue ->
match_job?(job, queue[:jobs])
end) || default_queue()
end
@spec default_queue :: keyword | nil
defp default_queue do
Enum.find(queues(), fn queue ->
queue[:jobs] == :default
end)
end
@spec match_job?(atom, atom | String.t() | list) :: boolean
defp match_job?(job, condition)
# e.g.
# match_job?(TestJob, TestJob)
# => true
# match_job?(TestJob, SampleJob)
# => false
defp match_job?(job, condition) when is_atom(condition), do: job == condition
# e.g.
# match_job?(TestJob, "TestJob")
# => true
# match_job?(TB.TestJob, "TB.*")
# => true
# match_job?(Elixir.TB.TestJob, "TB.*")
# => true
# match_job?(TestJob, "SampleJob")
# => false
defp match_job?(job, pattern) when is_binary(pattern) do
job_name = job |> Atom.to_string() |> String.trim_leading("Elixir.")
pattern =
pattern
|> Regex.escape()
|> String.replace("\\*", ".*")
regex = "^#{pattern}$" |> Regex.compile!()
String.match?(job_name, regex)
end
defp match_job?(job, jobs) when is_list(jobs) do
Enum.any?(jobs, fn pattern -> match_job?(job, pattern) end)
end
@doc """
Returns true if auto start is enabled.
"""
@spec auto_start? :: boolean
def auto_start? do
case Application.fetch_env(:task_bunny, :disable_auto_start) do
{:ok, true} -> false
_ -> true
end
end
@doc """
Returns true if worker is disabled.
"""
@spec disable_worker? :: boolean
def disable_worker? do
case Application.fetch_env(:task_bunny, :disable_worker) do
{:ok, true} -> true
_ -> disable_worker_on_env?()
end
end
defp disable_worker_on_env? do
env =
(System.get_env("TASK_BUNNY_DISABLE_WORKER") || "false")
|> String.downcase()
["1", "true", "yes"] |> Enum.member?(env)
end
@doc """
Disable auto start manually.
"""
@spec disable_auto_start :: :ok
def disable_auto_start do
:ok = Application.put_env(:task_bunny, :disable_auto_start, true)
end
@spec hosts_config() :: list
defp hosts_config do
case Application.fetch_env(:task_bunny, :hosts) do
{:ok, host_list} -> host_list
_ -> []
end
end
@doc """
Returns the list of failure backends.
It returns `TaskBunny.FailureBackend.Logger` by default.
"""
@spec failure_backend :: [atom]
def failure_backend do
case Application.fetch_env(:task_bunny, :failure_backend) do
{:ok, list} when is_list(list) -> list
{:ok, atom} when is_atom(atom) -> [atom]
_ -> [TaskBunny.FailureBackend.Logger]
end
end
@doc """
Returns the publisher pool size for poolboy. 15 by default
"""
@spec publisher_pool_size :: integer
def publisher_pool_size, do: Application.get_env(:task_bunny, :publisher_pool_size, 15)
@doc """
Returns the max overflow for the publisher poolboy. 0 by default
"""
@spec publisher_max_overflow :: integer
def publisher_max_overflow, do: Application.get_env(:task_bunny, :publisher_max_overflow, 0)
end