Packages

A Celery producer for Elixir. Currently supports the RabbitMQ broker, and only publishing tasks (not running them or retrieving their result).

Current section

Files

Jump to
ex_celery lib ex_celery.ex
Raw

lib/ex_celery.ex

defmodule ExCelery do
require Logger
use AMQP
use GenServer
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, [])
end
def init(opts) do
broker_url = Keyword.get(opts, :broker_url, "amqp://guest:guest@localhost")
{:ok, channel} = connect(broker_url)
state = %{
channel: channel,
broker_url: broker_url,
exchange: Keyword.get(opts, :exchange, "celery"),
}
{:ok, state}
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
def apply_async(pid, task, opts \\ []) do
GenServer.call(pid, {:apply_async, task, opts})
end
def handle_call({:apply_async, task, opts}, _from, state) do
%{channel: channel, exchange: exchange} = state
args = Keyword.get(opts, :args, [])
kwargs = Keyword.get(opts, :kwargs, %{})
{task_id, message} = make_task(task, args, kwargs)
result = Basic.publish(
channel,
exchange,
Keyword.get(opts, :routing_key, "celery"),
message,
[
content_type: "application/json",
content_encoding: Keyword.get(opts, :content_encoding, "utf-8"),
persistent: Keyword.get(opts, :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 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