Current section

Files

Jump to
rambla lib mix tasks rabbit_exchange.ex
Raw

lib/mix/tasks/rabbit_exchange.ex

defmodule Mix.Tasks.Rambla.Rabbit.Exchange do
@shortdoc "Operations with exchanges in RabbitMQ"
@moduledoc since: "0.6.0"
@moduledoc """
Mix task to deal with exchanges in the target RabbitMQ.
This is helpful to orchestrate target RabbitMQ when deploying
to docker. Allows to create and delete the exchange.
Loads the setting from `config :rambla, :amqp` if no connection
is provided in parameters.
## Command line options
* -c - the connection string
* -o - the list of options without spaces, separated by comma
## Options
### Options for `create`
* **`type`** - One of four possible values below. Defaults to `:direct`.
* `direct`
* `fanout`
* `topic`
* `headers`
* `durable` - If set, keeps the Exchange between restarts of the broker;
* `auto_delete` - If set, deletes the Exchange once all queues
unbind from it;
* `passive` - If set, returns an error if the Exchange does not
already exist;
* `internal` - If set, the exchange may not be used directly by
publishers, but only when bound to other exchanges. Internal exchanges are used to construct wiring that is not visible to applications.
* `no_wait` - If set, the declare operation is asynchronous.
Defaults to false.
* `arguments` - A list of arguments to pass when declaring
(of type AMQP.arguments/0). See the README for more information. Defaults to [].
### Options for `delete`
* `if_unused` - If set, the server will only delete the exchange
if it has no queue bindings.
* `no_wait` - If set, the delete operation is asynchronous.
"""
use Mix.Task
@switches [
connection: :string,
options: :string
]
@commands ~w|declare create delete|
require Logger
@impl Mix.Task
@doc false
def run([command, name | args]) when command in @commands do
Logger.configure(level: :error)
Process.flag(:trap_exit, true)
{opts, _} =
OptionParser.parse!(args, aliases: [o: :options, c: :connection], strict: @switches)
connection =
case Keyword.get(opts, :connection, Application.get_env(:rambla, :amqp)) do
uri when is_binary(uri) ->
uri
params when is_list(params) ->
port = if params[:port], do: ":#{params[:port]}", else: ""
"amqp://#{params[:username]}:#{params[:password]}@#{params[:host]}#{port}"
nil ->
Mix.raise(
"The connection string must be either passed as -c option or set in `config :rambla, :amqp`"
)
end
with {:ok, conn} <- AMQP.Connection.open(connection),
{:ok, chan} = AMQP.Channel.open(conn),
opts =
opts
|> Keyword.get(:options, "")
|> String.replace(~r/:(?=\d)/, ": ")
|> String.replace(~r/:(?=\w)/, ": :"),
{opts, _} <- Code.eval_string("[" <> opts <> "]"),
:ok <- do_command(chan, String.to_atom(command), name, opts) do
Mix.shell().info("Success.")
else
amqp_base_error ->
Mix.raise("Cannot execute command on target. Error:\n" <> inspect(amqp_base_error))
end
end
@doc false
def run(_),
do:
Mix.raise(
"Usage: mix rambla.rabbit.exchange (" <> Enum.join(@commands, "|") <> ") name [opts]"
)
@spec do_command(
chan :: AMQP.Channel.t(),
command :: atom(),
name :: binary(),
opts :: keyword()
) :: :ok | {:error, any()}
defp do_command(chan, :create, name, opts),
do: do_command(chan, :declare, name, opts)
defp do_command(chan, :declare, name, opts) do
{type, opts} = Keyword.pop(opts, :type, :direct)
AMQP.Exchange.declare(chan, name, type, opts)
end
defp do_command(chan, :delete, name, opts) do
{_type, opts} = Keyword.pop(opts, :type, :direct)
AMQP.Exchange.delete(chan, name, opts)
end
end