Current section
Files
Jump to
Current section
Files
lib/ex_celery.ex
defmodule ExCelery do
require Logger
use AMQP
use GenServer
@default_broker_url "amqp://guest:guest@localhost"
@default_exchange "celery"
def start_link(options \\ []) do
broker_url = Keyword.get(options, :broker_url, default_config(:broker_url, @default_broker_url))
{:ok, channel} = connect(broker_url)
state = %{
channel: channel,
broker_url: broker_url,
exchange: Keyword.get(options, :exchange, default_config(:exchange, @default_exchange)),
}
GenServer.start_link(__MODULE__, state, Keyword.merge([name: __MODULE__], options))
end
def apply_async(task, options \\ []) do
name = Keyword.get(options, :name, __MODULE__)
GenServer.call(name, {:apply_async, task, options})
end
def handle_call({:apply_async, task, options}, _from, state) do
%{channel: channel, exchange: exchange} = state
args = Keyword.get(options, :args, [])
kwargs = Keyword.get(options, :kwargs, %{})
{task_id, message} = make_task(task, args, kwargs)
result = Basic.publish(
channel,
exchange,
Keyword.get(options, :routing_key, "celery"),
message,
[
content_type: "application/json",
content_encoding: Keyword.get(options, :content_encoding, "utf-8"),
persistent: Keyword.get(options, :persistent, true),
]
)
case result do
:ok -> {:reply, {:ok, task_id}, state}
e -> {:reply, e, state}
end
end
def handle_cast(request, state) do
super(request, state)
end
def handle_info({:DOWN, _, :process, _pid, _reason}, state) do
%{broker_url: broker_url} = state
{:ok, channel} = connect(broker_url)
{:noreply, {broker_url, channel}}
end
defp default_config(key, fallback) do
Application.get_env(:ex_celery, key, fallback)
end
defp connect(broker_url, attempt \\ 0) do
case Connection.open(broker_url) do
{:ok, connection} ->
Process.monitor(connection.pid)
Logger.info "Connected to broker #{broker_url}"
Channel.open(connection)
{:error, e} ->
retry_secs = min((attempt + 1) * 2, 32)
Logger.error "Cannot connect to #{broker_url}: #{inspect e}"
Logger.error "Trying again in #{retry_secs} seconds..."
:timer.sleep(retry_secs * 1000)
connect(broker_url, attempt + 1)
end
end
defp make_task(task, args, kwargs) do
task_id = UUID.uuid4()
message = %{
id: task_id,
task: task,
args: args,
kwargs: kwargs,
}
{task_id, Poison.encode!(message)}
end
end