Skip to content

[Messenger] make it easier to consume third-party messages #32049

@Tobion

Description

@Tobion

The messenger component works pretty good by default if you send messenges with the messenger component and also consume them this way. But if you need to consume messages from a third-party there are several problems which requires alot of thought to make this work.

Serialization does not work - let keep track in #33912

External messages do not have the headers/content that sf serializer requires. External messages are likely not encoded using php serialize so the default PhpSerializer does not work. But also the SymfonySerializer can't work because external messages won't have the type header to know which class to deserialize to. This can be solved using a custom serializer. So maybe this issue is only about documenting an example custom Serializer to fix this gotcha. Having a solution that works by default could be possible using a GenericMessage class. See #31230 Or we implement some default JSON Serializer that uses \JsonSerializable and custom callback like $message = $messageClass::fromJson($encodedEnvelope['body']). So people would only need to configure the default message class of a transport and fromJson. No need to implement a whole custom serializer which requires handling headers etc.

Retry does not work - fixed by #32053

As said above, external messages do not have the SF messenger headers. This also means, they do not have any Stamps. Without the SentStamp, the retry logic that is enabled by default, does not work. You get the following warning.

16:11:12 WARNING [messenger] Message will not be retried because the SentStamp is missing and so the target sender cannot be determined.

We need to find a solution that does not require the SentStamp. Using the SentStamp for retry seems strange anyway. You can route a single message to several transports. But the retry logic just uses the last sender for redelivery which is arbitrary.
The solution I see: In the Worker just use the current transport also for redelivery. That should cover 99% of all cases and would be the same behavior as now. If somebody needs customization we could even introduce a retry_transport config option on the transport. This way people could send retries to a different transport.

The current workaround is to write a custom transport that adds a fake SentStamp when receiving messages.

Routing to correct bus does not work - fixed by #34247

The RouteableMessageBus requires the BusNameStamp to know which bus the messages should be dispatched to. So as soon as you have more than one bus, third-party messages can't be consumed without having to manually specify the bus option like bin/console messenger:consume mytransport --bus=mybus every time. In general I don't think the --bus option is a good thing. If you accidentally specify the wrong bus, hell can break lose. I'd prefer a config option on the transport level where you can specify the bus that all messages from this transport should go. It can default to null which uses the current BusNameStamp logic so people using SF messenger to send and receive messages won't have to worry about this. For consuming third-party messages you just set this config option. Then we don't even need the --bus option on the worker anymore IMO. It's just too error-prone and repetitive as you need to specify each time you run the worker. Also the option that shouldn't be used can confuse people.

Current workaround is also to add a BusNameStamp in a custom transport.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions