--- title: "Consuming messages" description: "Consuming messages — a normal Symfony Messenger handler, routed by message class; BabelQueue decodes the envelope and bridges retry + trace." source: https://babelqueue.com/docs/symfony/1.x/consuming-messages/ updated: 2026-06-07T00:00:00.000Z --- # Consuming messages Consuming is a normal Messenger handler. The serializer decodes the inbound envelope, uses the [URN → class map](/docs/symfony/1.x/configuration/#urn--message-class-map) to rebuild your message via `fromBabelPayload()`, and Messenger routes it to the handler for that class. ## A handler ```php use Symfony\Component\Messenger\Attribute\AsMessageHandler; #[AsMessageHandler] final class OnOrderCreated { public function __invoke(OrderCreated $message): void { // $message->orderId === 1042 } } ``` Run the worker exactly as you normally would: ```bash php bin/console messenger:consume babel ``` ## How it maps to Messenger - **Routing** is Messenger's job: the decoded message class is routed to its handler. An inbound URN with no entry in the `messages` map cannot be rebuilt — keep the registry in sync with the URNs you consume. - **Retry** bridges both ways: Messenger's `RedeliveryStamp` ⇄ the envelope's top-level `attempts`. Your existing Messenger retry strategy applies unchanged. - **Tracing**: the inbound `trace_id` is attached as a `BabelTraceStamp`. With `babelqueue.messenger.trace_middleware` on the bus, any message a handler dispatches inherits that `trace_id`, so a whole chain of work stays in one trace. ## Cross-language Because the wire format is the canonical envelope, a message your Symfony app consumes may have been produced by **any** BabelQueue SDK — a Laravel app, a Go service, a Python worker — and vice-versa. The URN is the only shared contract; no class is shared across languages. See the [wire contract](/docs/spec/1.x/envelope/) and the [cross-language example](/docs/examples/1.x/cross-language-redis/).