README.md

# Overview

`rabbit_mq` is an opinionated RabbitMQ client to help _you_ build balanced and consistent Consumers and Producers.

## Documentation

The full documentation is published on [hex](https://hexdocs.pm/rabbit_mq/).

The following modules are provided;

* `RabbitMQ.Topology`
* `RabbitMQ.Consumer`
* `RabbitMQ.Producer`

## Example usage

1. Define network topology
2. Define Producers
3. Define Consumers
4. Supervise
5. Start producing and consuming messages

### Define network topology

```elixir
defmodule Topology do
  use RabbitMQ.Topology,
    exchanges: [
      {"customer", :topic,
        [
          {"customer.created", "customer/customer.created", durable: true},
          {"customer.updated", "customer/customer.updated", durable: true},
          {"#", "customer/#"}
        ], durable: true}
    ]
end
```

### Define Producers

```elixir
defmodule CustomerProducer do
  use RabbitMQ.Producer, exchange: "customer", worker_count: 3

  def customer_updated(updated_customer) when is_map(updated_customer) do
    # See https://hexdocs.pm/amqp/AMQP.Basic.html#publish/5 for all available options.
    opts = [
      content_type: "application/json",
      correlation_id: UUID.uuid4(),
      mandatory: true
    ]

    payload = Jason.encode!(updated_customer)

    publish(payload, "customer.updated", opts)
  end
end
```

### Define Consumers

```elixir
defmodule CustomerConsumer do
  use RabbitMQ.Consumer, queue: "customer/customer.updated", worker_count: 3

  require Logger

  def consume(payload, meta, channel) do
    Logger.info(payload)
    ack(channel, meta.delivery_tag)
  end
end
```

### Supervise

Start as normal under your existing supervision tree.

⚠️ Please note that the `Topology` module will terminate gracefully as soon as the network is configured.

```elixir
children = [
  Topology,
  CustomerConsumer,
  CustomerProducer,
  # ...and more
]

Supervisor.start_link(children, strategy: :one_for_one)
```

### Start producing and consuming messages

To publish, simply call your pre-defined methods.

```elixir
CustomerProducer.customer_updated(updated_customer)
```

To consume, update the `consume/3` implementation.

## Balanced performance and reliability

The RabbitMQ modules are pre-configured with sensible defaults and follow design principles that improve and delicately balance both performance _and_ reliability.

This has been possible through

* a) extensive experience of working with Elixir and RabbitMQ in production; _and_
* b) meticulous consultation of the below (and more) documents and guides.

⚠️ While most of the heavy-lifting is provided by the library itself, reading through the documents below before running _any_ application in production is thoroughly recommended.

* [Connections](https://www.rabbitmq.com/connections.html)
* [Channels](https://www.rabbitmq.com/channels.html)
* [Reliability Guide](https://www.rabbitmq.com/reliability.html)
* [Publisher Confirms](https://www.rabbitmq.com/confirms.html#publisher-confirms)
* [Consumer Acknowledgements and Publisher Confirms](https://www.rabbitmq.com/confirms.html)
* [Consumer Acknowledgement Modes and Data Safety Considerations](https://www.rabbitmq.com/confirms.html#acknowledgement-modes)
* [Consumer Prefetch](https://www.rabbitmq.com/consumer-prefetch.html)
* [Production Checklist](https://www.rabbitmq.com/production-checklist.html)
* [RabbitMQ Best Practices](https://www.cloudamqp.com/blog/2017-12-29-part1-rabbitmq-best-practice.html)
* [RabbitMQ Best Practice for High Performance (High Throughput)](https://www.cloudamqp.com/blog/2018-01-08-part2-rabbitmq-best-practice-for-high-performance.html)