Packages
rambla
0.14.3
1.5.0
1.4.2
1.4.1
1.4.0
1.3.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.0
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
0.13.0
0.12.2
0.12.1
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Easy publishing to many different targets. Supported back-ends: - Rabbit [Amqp](https://hexdocs.pm/amqp/) - Redis [Redix](https://hexdocs.pm/redix) - Http [:httpc](http://erlang.org/doc/man/httpc.html) - Smtp [:gen_smtp](https://hexdocs.pm/gen_smtp) - Slack [Envío](https://hexdocs.pm/envio)
Current section
Files
Jump to
Current section
Files
lib/rambla/connections/amqp.ex
defmodule Rambla.Amqp do
@moduledoc """
Default connection implementation for 🐰 Rabbit.
`publish/2` accepts the following options:
- `exchange` [`binary()`, **mandatory**] the exchange to publish to
- `queue` [`binary()`, **optional**] if passed, the queue will be created
and bound to the exchange; it’s slowing down publishing, but safer
for the cold RebbatMQ installation
- `declare?`[`boolean()`, **optional**, _default_: `true`] if false
is passed, the exchange would not be declared; use it if the exchange
already surely exists to speed up the publishing
- `routing_key` [`binary()`, **optional**, _default_: `""`] if passed,
used as a routing key
- `options` [`keyword()`, **optional**, _default_: `[]`] the options
to be passed as is to call to `AMQP.Basic.publish/5`
---
Since `v0.6.0` provides two `mix` tasks:
- `mix rambla.rabbit.exchange` Operations with exchanges in RabbitMQ
- `mix rambla.rabbit.queue` Operations with queues in RabbitMQ
Tasks support arguments to be passed to RabbitMQ instance. Usage example:
```
mix rambla.rabbit.queue declare foo -o durable:true
```
"""
defmodule ChannelPool do
@moduledoc false
@amqp_pool_size Application.get_env(:rambla, :amqp_pool_size, 32)
use Tarearbol.Pool, pool_size: @amqp_pool_size
@spec publish(%Rambla.Connection.Config{}, binary() | map() | list()) ::
{:ok | :replace, Rambla.Connection.Config.t()}
defsynch publish(%Rambla.Connection.Config{conn: conn, opts: opts}, message) do
message =
case message do
message when is_binary(message) -> message
%{} = message -> Jason.encode!(message)
[{_, _} | _] = message -> message |> Map.new() |> Jason.encode!()
message -> inspect(message)
end
{_, %{chan: %{__struct__: AMQP.Channel} = chan}} =
reply =
case payload!() do
%{conn: ^conn, chan: %{__struct__: AMQP.Channel}} = cfg ->
{:ok, cfg}
%{} = cfg ->
if not is_nil(cfg[:chan]), do: apply(AMQP.Channel, :close, [cfg[:chan]])
{:replace, %{conn: conn, chan: AMQP.Channel |> apply(:open, [conn]) |> elem(1)}}
end
with %{exchange: exchange} <- opts,
declare? <- Map.get(opts, :declare?, true),
if(declare?, do: apply(AMQP.Exchange, :declare, [chan, exchange])),
:ok <- queue!(chan, opts),
do:
apply(AMQP.Basic, :publish, [
chan,
exchange,
Map.get(opts, :routing_key, ""),
message,
Map.get(opts, :options, [])
])
reply
end
@spec queue!(chan :: AMQP.Channel.t(), map()) :: :ok
defp queue!(chan, %{queue: queue, exchange: exchange}) do
with {:ok, %{consumer_count: _, message_count: _, queue: ^queue}} <-
apply(AMQP.Queue, :declare, [chan, queue]),
do: apply(AMQP.Queue, :bind, [chan, queue, exchange])
end
defp queue!(_, %{exchange: _exchange}), do: :ok
end
@with_amqp match?({:module, _}, Code.ensure_compiled(AMQP.Channel))
@behaviour Rambla.Connection
@impl Rambla.Connection
def connect(params) when is_list(params) do
if not @with_amqp or is_nil(params[:host]),
do:
raise(Rambla.Exceptions.Connection,
value: params,
expected: "🐰 configuration with :host key"
)
case ChannelPool.start_link() do
{:ok, pool} -> Process.link(pool)
{:error, {:already_started, pool}} -> Process.link(pool)
end
maybe_amqp(params)
end
@impl Rambla.Connection
def publish(%Rambla.Connection.Config{} = conn, message)
when is_binary(message) or is_list(message) or is_map(message),
do: ChannelPool.publish(conn, message)
if @with_amqp do
defp maybe_amqp(params) do
case AMQP.Connection.open(params) do
{:ok, conn} ->
Process.link(conn.pid)
%Rambla.Connection{
conn: %Rambla.Connection.Config{conn: conn},
conn_type: __MODULE__,
conn_pid: conn.pid,
conn_params: params,
errors: []
}
error ->
%Rambla.Connection{
conn: %Rambla.Connection.Config{},
conn_type: __MODULE__,
conn_pid: nil,
conn_params: params,
errors: [error]
}
end
end
else
defp maybe_amqp(params) do
error =
Rambla.Exceptions.Connection.exception(
source: __MODULE__,
info: params,
reason: "🐰 AMQP should be explicitly included to use this functionality"
)
%Rambla.Connection{
conn: %Rambla.Connection.Config{},
conn_type: __MODULE__,
conn_pid: nil,
conn_params: params,
errors: [error]
}
end
end
end