{"id":16482322,"url":"https://github.com/uesteibar/errol","last_synced_at":"2025-03-21T07:30:39.725Z","repository":{"id":62429038,"uuid":"129794005","full_name":"uesteibar/errol","owner":"uesteibar","description":"Orchestrate RabbitMQ consumers in an OTP manner 📬","archived":false,"fork":false,"pushed_at":"2018-09-26T14:12:42.000Z","size":98,"stargazers_count":27,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-17T22:27:36.285Z","etag":null,"topics":["amqp","amqp-client","elixir","elixir-lang","elixir-library","rabbitmq","rabbitmq-client"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/errol","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uesteibar.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-04-16T19:19:21.000Z","updated_at":"2023-12-25T13:50:45.000Z","dependencies_parsed_at":"2022-11-01T20:06:00.193Z","dependency_job_id":null,"html_url":"https://github.com/uesteibar/errol","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uesteibar%2Ferrol","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uesteibar%2Ferrol/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uesteibar%2Ferrol/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uesteibar%2Ferrol/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uesteibar","download_url":"https://codeload.github.com/uesteibar/errol/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244757205,"owners_count":20505349,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amqp","amqp-client","elixir","elixir-lang","elixir-library","rabbitmq","rabbitmq-client"],"created_at":"2024-10-11T13:10:23.048Z","updated_at":"2025-03-21T07:30:39.402Z","avatar_url":"https://github.com/uesteibar.png","language":"Elixir","readme":"# Errol\n\n[![Build Status](https://travis-ci.org/uesteibar/errol.svg?branch=master)](https://travis-ci.org/uesteibar/errol)\n[![Hex Version](https://img.shields.io/hexpm/v/errol.svg)](https://hex.pm/packages/errol)\n\nAn opinionated framework to run and orchestrate [RabbitMQ](https://www.rabbitmq.com/) consumers.\n\n## Index\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Running Locally](#running-locally)\n- [Roadmap](#roadmap)\n- [Contributing](#contributing)\n- [Credit](#credit)\n\n## Installation\n\nThe package can be installed by adding `errol` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [{:errol, \"~\u003e 0.2.0\"}]\nend\n```\n\nYou should also update your application list to include `:errol`:\n\n```elixir\ndef application do\n  [applications: [:errol]]\nend\n```\n\nDocumentation can be found at [https://hexdocs.pm/errol](https://hexdocs.pm/errol).\n\n## Usage\n\nTo bind consumers to queue, you can use the `Errol.Wiring` module:\n\n```elixir\ndefmodule Sample.Wiring do\n  use Errol.Wiring\n\n  connection(\"amqp://guest:guest@localhost\")\n\n  @exchange \"/users\"\n  @exchange_type :topic\n\n  # You can pass a reference to a function with arity of 1\n  consume(\"account_created\", \"users.account.created\", \u0026UsersConsumer.account_created/1)\n\n  # or even an anonymous function\n  consume(\"account_updated\", \"users.account.updated\", fn message -\u003e ... end)\nend\n```\n\nFor more complex setups, you can add **middleware** and **group** different\nconsumers for more granularity.\n\n```elixir\ndefmodule Sample.Wiring do\n  use Errol.Wiring\n\n  connection(\"amqp://guest:guest@localhost\")\n\n  @exchange \"/users\"\n  @exchange_type :topic\n\n  # Use pipe_before/1, pipe_after/1 or pipe_error/1 to run middleware functions\n  # middlewares declared outside of a group will run for every consumer\n  pipe_after(\u0026Sample.StatisticsMiddleware.track/2)\n\n  # Use the `group` macro to group consumers with specific middleware\n  group :account do\n    # This middlewares will run only for consumers in the :account group\n    pipe_before(\u0026Errol.Middleware.Json.parse/2)\n    pipe_error(\u0026Errol.Middleware.Retry.basic_retry/2)\n\n    consume(\"account_created\", \"users.account.created\", \u0026UsersConsumer.account_created/1)\n    consume(\"account_updated\", \"users.account.updated\", fn message -\u003e ... end)\n  end\n\n  group :photos do\n    pipe_before(\u0026Sample.ImagesMiddleware.uncompress/2)\n\n    consume(\"profile_photo_uploaded\", \"users.profile.photo.uploaded\", fn message -\u003e ... end)\n  end\nend\n```\n\nAt this point, the only thing left is to run `Sample.Wiring` as a _supervisor_ in your `application.ex` file.\n\nThis is important because if _RabbitMQ_ goes down, all wiring supervisors will\nbe killed, so if they are not in the supervision tree they will not be restarted.\n\n```elixir\ndefmodule Sample.Application do\n  use Application\n\n  def start(_type, _args) do\n    import Supervisor.Spec\n\n    children = [\n      supervisor(Sample.Wiring, []),\n      ...\n    ]\n\n    opts = [strategy: :one_for_one, name: Sample.Supervisor]\n    Supervisor.start_link(children, opts)\n  end\nend\n```\n\nVoilà! This will spin up the following supervision tree:\n\n```\n\n                                      --------------------\n                                     | Sample.Application |\n                                      --------------------\n                                               |\n                                               |\n                                        ---------------\n                                       | Sample.Wiring |\n                                        ---------------\n                                               |\n                  _____________________________|_____________________________\n                 |                             |                             |\n                 |                             |                             |\n   ---------------------------    ---------------------------    -------------------------\n  | :account_created_consumer |  | :account_updated_consumer |  | :profile_photo_uploaded |\n   ---------------------------    ---------------------------    -------------------------\n       .     .     .     .           .    .    .    .    .          .     .     .     .\n       .     .     .     .           .    .    .    .    .          .     .     .     .\n       .     .     .     .           .    .    .    .    .          .     .     .     .\n       .     .     .     .           .    .    .    .    .          .     .     .     .\n       .     .     .     .           .    .    .    .    .          .     .     .     .\n\n                       New monitored process per each message received\n\n\n```\n\nCompatibility with other AMQP implementations exists but is not guaranteed (at least for now 😁).\n\n## Running locally\n\nClone the repository\n```bash\ngit clone git@github.com:uesteibar/errol.git\n```\n\nInstall dependencies\n```bash\ncd errol\nmix deps.get\n```\n\nTo run the tests (you will need [docker](https://www.docker.com/) installed)\n```bash\n./scripts/test_prepare.sh\nmix test\n```\n\n## Roadmap\n\n- [x] Allow to retry messages from `pipe_error` middleware. This would enable users to handle retries and requeuing to dead letter exchange.\n- [x] Allow to reject messages from `pipe_before` middleware.\n- [x] Handle RabbitMQ outages, following the great explanation in the [amqp hex documentation](https://hexdocs.pm/amqp/readme.html#stable-rabbitmq-connection).\n- [ ] Allow to specify number of workers per consumer. [Poolboy](https://github.com/devinus/poolboy) would come handy here.\n- [ ] Publish messages.\n\n## Contributing\n\nPull requests are always welcome =)\n\nThe project uses [standard-changelog](https://github.com/conventional-changelog/conventional-changelog) to update the _Changelog_ with each commit message and upgrade the package version.\nFor that reason every contribution must have a title and body that follows the [conventional commits standard](https://conventionalcommits.org/) conventions (e.g. `feat(consumer): Consume it all`).\n\nTo make this process easier, you can do the following:\n\nInstall `commitizen` and `cz-conventional-changelog` globally\n```bash\nnpm i -g commitizen cz-conventional-changelog\n```\n\nSave `cz-conventional-changelog` as default\n```bash\necho '{ \"path\": \"cz-conventional-changelog\" }' \u003e ~/.czrc\n```\n\nInstead of `git commit`, you can now run\n```\ngit cz\n```\nand follow the instructions to generate the commit message.\n\n### Credit\n\n🎉 Special thanks to [**@pma**](https://github.com/pma) for the amazing work on the [amqp hex](https://github.com/pma/amqp).\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuesteibar%2Ferrol","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuesteibar%2Ferrol","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuesteibar%2Ferrol/lists"}