The raven that gets lost

Exercise 3 of 6 in chapter 7 · 250 XP · 5 objectives checked by tests

Topics covered: retry_strategyfailure_transportRetriesRedeliveryStamp

A raven does not always arrive. The winds turn, dark towers scramble the routes… and some lands are simply out of reach.

The tavern now has a Voliere (aviary) service: it is the one that releases the birds. When the destination cannot be reached, it throws a VoliereIndisponible (aviary unavailable). Today, such an error would make the confirmation vanish. You need to retry, and then, if nothing works, set the message aside instead of losing it.

Your mission

  1. In the handler, hand the sending over to the aviary ($this->voliere->envoyer(...), “send”). Let the exception bubble up: it is the failure signal.
  2. In messenger.yaml:
    • give the async transport a retry_strategy: 2 retries, 1 second of waiting, doubled each time;
    • add an echoues (failed) transport, and designate it as the failure_transport;
    • during the tests, both transports live in memory, with a retry delay of zero: a test must not spend its time waiting.

What Messenger does on its own

When a handler throws an exception, the worker does not throw the message away: it puts it back in the queue with a delay, and tries again. After the last retry, the message goes to the failure transport. Nothing is lost, and the main queue is not blocked.

Each retry leaves a mark on the envelope, a stamp (RedeliveryStamp): you know how many times the message has already been tried.

In the console

messenger:consume async --limit=5
messenger:failed:show
messenger:failed:retry

The first one handles the queue (try a reservation for Sauron in the “Requests” tab). The second lists the messages set aside, the third replays them, once the winds have calmed down.

Good habit

Retrying only makes sense for a temporary failure: a crowded aviary, a service that responds badly. An error that will happen again in exactly the same way (invalid data, for example) does not deserve a retry: better to set it aside right away.