{"id":22511142,"url":"https://github.com/renderedtext/ex-tackle","last_synced_at":"2025-08-19T22:32:03.607Z","repository":{"id":49973970,"uuid":"61719845","full_name":"renderedtext/ex-tackle","owner":"renderedtext","description":"💯 percent reliable microservice communication","archived":false,"fork":false,"pushed_at":"2024-07-17T15:52:11.000Z","size":181,"stargazers_count":48,"open_issues_count":4,"forks_count":14,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-12-07T02:09:07.941Z","etag":null,"topics":["amqp","asynchronous","elixir","microservices","rabbitmq","semaphore-open-source"],"latest_commit_sha":null,"homepage":"","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/renderedtext.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-22T13:06:31.000Z","updated_at":"2024-07-12T11:26:27.000Z","dependencies_parsed_at":"2023-01-18T19:02:18.685Z","dependency_job_id":"bb71aefb-b4b4-490f-82b7-0f8e2f6740a8","html_url":"https://github.com/renderedtext/ex-tackle","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renderedtext%2Fex-tackle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renderedtext%2Fex-tackle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renderedtext%2Fex-tackle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/renderedtext%2Fex-tackle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/renderedtext","download_url":"https://codeload.github.com/renderedtext/ex-tackle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230374115,"owners_count":18216041,"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","asynchronous","elixir","microservices","rabbitmq","semaphore-open-source"],"created_at":"2024-12-07T02:09:15.193Z","updated_at":"2025-08-19T22:32:03.600Z","avatar_url":"https://github.com/renderedtext.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tackle\n\n[![Build Status](https://semaphore.semaphoreci.com/badges/ex-tackle/branches/master.svg?style=shields)](https://semaphore.semaphoreci.com/projects/ex-tackle)\n\nTackles the problem of processing asynchronous jobs in reliable manner\nby relying on RabbitMQ.\n\nYou should also take a look at [Ruby Tackle](https://github.com/renderedtext/tackle).\n\n## Why should I use tackle?\n\n- It is ideal for fast microservice prototyping\n- It uses sane defaults for queue and exchange creation\n- It retries messages that fail to be processed\n- It stores unprocessed messages into a __dead__ queue for later inspection\n\n## Installation\n\nAdd the following to the list of your dependencies:\n\n``` elixir\ndef deps do\n  [\n    {:tackle, github: \"renderedtext/ex-tackle\"}\n  ]\nend\n```\n\nAlso, add it to the list of your applications:\n\n``` elixir\ndef application do\n  [applications: [:tackle]]\nend\n```\n\n## Publishing messages to an exchange\n\nTo publish a message to an exchange:\n\n``` elixir\noptions = %{\n  url: \"amqp://rabbitmq:5672\",\n  exchange: \"test-exchange\",\n  routing_key: \"test-messages\",\n}\n\nTackle.publish(\"Hi!\", options)\n```\n\nThe previous example will open a new connection, create the exchange if it\ndoesn't exists, and close the connection. This makes sure that everything is\nplace, but has pretty bad performance.\n\nFor fast publishing of multiple messages, open a channel manually, make sure\nthat the exchange exists, and publish messages with `Tackle.Exchange.publish`.\nExample:\n\n``` elixir\n{:ok, c}  = Tackle.Connection.open(:publisher, \"amqp://rabbitmq:5672\")\nchannel   = Tackle.Channel.create(c)\nexchange  = Tackle.Exchange.create(channel, \"test-exchange\")\nroute_key = \"hello\"\n\n(1..1_000) |\u003e Enum.each(fn _ -\u003e\n  Tackle.Exchange.publish(channel, exchange, \"Hi!\", routing_key)\nend)\n```\n\n## Consuming messages from an exchange\n\nFirst, declare a consumer module:\n\n``` elixir\ndefmodule TestConsumer do\n  use Tackle.Consumer,\n    url: \"amqp://rabbitmq:5672\",\n    exchange: \"test-exchange\",\n    routing_key: \"test-messages\",\n    service: \"my-service\"\n\n  def handle_message(message) do\n    IO.puts \"A message arrived. Life is good!\"\n\n    IO.puts message\n  end\nend\n```\n\nAnd then start it to consume messages:\n\n``` elixir\nTestConsumer.start_link\n```\n\n## Rescuing dead messages\n\nIf you consumer is broken, or in other words raises an exception while handling\nmessages, your messages will end up in a dead messages queue.\n\nTo rescue those messages, you can use `Tackle.republish`:\n\n``` elixir\ndead_queue_name = \"my-service.test-message.dead\"\n\noptions = {\n  url: \"amqp://rabbitmq:5672\",\n  queue: dead_queue_name,\n  exchange: \"test-exchange\",\n  routing_key: \"test-messages\",\n  count: 1\n}\n\nTackle.republish(options)\n```\n\nThe above will pull one message from the `dead_queue_name` and publish it on the\n`test-exchange` exchange with `test-messages` routing key.\n\nTo republish multiple messages, use a bigger `count` number.\n\n## Opening multiple channels through the same connection\n\nBy default each channel (consumer) opens separate connection to the server.\n\nIf you want to reduce number of opened connections from one Elixir application\nto RabbitMQ server, you can map multiple channels to single connection.\n\nEach connection can have name, supplied as optional parameter `connection_id`.\nAll consumers that have the same connection name share single connection.\n\nParameter `connection_id` is optional and if not supplied,\n`connection_id` is set to `:default`.\nValue `:default` has exceptional semantic: all channels with `connection_id`\nset to `:default` use separate connections - one channel per `:default` connection.\n\n#### To use this feature\n\nIn consumer specification use `connection_id` parameter:\n```\ndefmodule Consumer do\n  use Tackle.Consumer,\n    url: \"...\",\n    connection_id: :connection_identifier,\n    ...\n```\n\n## License\n\nThis software is licensed under [the Apache 2.0 license](LICENSE).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenderedtext%2Fex-tackle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frenderedtext%2Fex-tackle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frenderedtext%2Fex-tackle/lists"}