lud
Catching NO_ROUTE from AMQP.Basic.publish
Hi everyone!
I wrote a unit test where I want to ensure that the app is able to connect to RabbitMQ (using Broadway), so the test will start Broadway, then publish to some exchange, and expect a message from the Broadway processor.
The problem is that it takes time for the Broadway producer to declare the exchange and bind the queue, so in my test when I publish the message it is not routed.
My current solution is to add a small sleep but it is not reliable (and slows down tests).
{:ok, rmq_consumer} = consumer_mod.start_link(job_handler: job_handler, start_mode: :normal)
# Generate a random string to validate that we receive this specific
# message.
randstr = Ecto.UUID.generate()
payload = Jason.encode!(%{"randstr" => randstr})
# Connect to RMQ and deliver the payload to the configured exchange.
# Currently I have not figured a way to ensure that the queue was declared
# and to republish otherwise, so we sleep for one second.
config = consumer_mod.config()
{:ok, conn} = AMQP.Connection.open(config.connection)
{:ok, chan} = AMQP.Channel.open(conn)
Process.sleep(1000)
:ok = ensure_routed_publish(chan, config.exchange, "", payload)
# We should receive the same random string from our test handler
assert_receive {:rmq_str, ^randstr}, 1000
I tried to fiddle with AMQP.Confirm.select, the :mandatory option, the wait_confirm_or_die function, but it does not work. Everytime AMQP will happily tell me that everything is fine though my message will never be routed as with select I can see the error in the logs.
How can I write the ensure_routed_publish/4 function so it returns {:error, _} when the message is not routed so I can retry it and avoid the sleeping?
Thank you.
Marked As Solved
BradS2S
You can use return to register a handler to deal with returned messages.
If you get this message: {:basic_return, payload, meta}, send it again.
Also Liked
lud
Yes this is more or less what I did:
defp ensure_routed_publish(chan, exchange, key, payload) do
AMQP.Confirm.select(chan)
AMQP.Confirm.register_handler(chan, self())
AMQP.Basic.return(chan, self())
publish_loop(chan, exchange, key, payload)
end
defp publish_loop(chan, exchange, key, payload) do
:ok = AMQP.Basic.publish(chan, exchange, key, payload, mandatory: true)
receive do
{:basic_return, _, %{reply_text: "NO_ROUTE"}} ->
receive do
{:basic_ack, _, _} ->
Process.sleep(50)
publish_loop(chan, exchange, key, payload)
end
{:basic_ack, _, _} ->
:ok
after
5000 -> flunk("could not deliver message to RabbitMQ")
end
end
(It is in a test so we know the queue will exist at some point.)
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








