SIGN IN SIGN UP

feature #65144 [FrameworkBundle][Messenger][Scheduler] Add framework.scheduler.use_messenger_routing (lyrixx)

This PR was merged into the 8.2 branch.

Discussion
----------

[FrameworkBundle][Messenger][Scheduler] Add framework.scheduler.use_messenger_routing

| Q             | A
| ------------- | ---
| Branch?       | 8.2
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | yes
| Issues        |
| License       | MIT

By default a scheduled message does not go through Messenger routing: `SchedulerTransport` hands it to the worker, which runs it inline. Wrapping a message in a `RedispatchMessage` sends it through routing, but nothing points you at that class, and until #65143 you also had to repeat the transport name that `framework.messenger.routing` (or `#[AsMessage]`) already knows.

This PR adds `framework.scheduler.use_messenger_routing`, so that routing applies to scheduled messages the way it applies everywhere else:

- `framework.scheduler.use_messenger_routing`: `bool|null`, defaults to `null`. `null` keeps the current behavior, tasks run inline, and is deprecated: the option will default to `true` in 9.0.
- When `true`, `SchedulerTransport` wraps every scheduled message, attribute-declared tasks and `#[AsSchedule]` provider messages alike, in a `RedispatchMessage`, unless it already is one. A `transports` option set on a task still takes precedence.
- The deprecation is triggered from `SchedulerTransport::get()`, only when an unwrapped message is actually yielded, so an install with the component present and nothing due stays quiet instead of warning on every container build.
- `symfony/scheduler` now requires and conflicts on `symfony/messenger` `^8.2`: below that version, `RedispatchMessageHandler` attaches an empty `TransportNamesStamp`, which makes the option a silent no-op.

Worth knowing before turning it on in an existing app: if a scheduled message's class has a route, and a `'*'` catch-all counts, the task is sent to that transport instead of running inline. A consumer must be running for it, or the task is queued and never executes, with nothing logged beyond "Sending message". From there on, retries, the failure transport and serialization of the message arguments apply like for any other async message. To keep a task inline, route its class, or set `transports: 'sync'` on the attribute, to a `sync://` transport.

Two things that wrapping used to break are fixed here, because the option turns them from an exception into the common case:

- The scheduler events carried the `RedispatchMessage` rather than the scheduled message, so a listener matching on the task class silently stopped matching, `shouldCancel()` included. `PreRunEvent`, `PostRunEvent` and `FailureEvent` now always carry the scheduled message. On a routed task the pair fires twice: in the scheduler worker when the task is dispatched, with a `null` result, and in the consumer when it actually runs.
- `ScheduledStamp` carries the trigger, so a task whose trigger holds a closure, `CallbackTrigger` or anything decorating one, died at send time with `Serialization of 'Closure' is not allowed` and never ran. `ScheduledStamp` now serializes the trigger as a description, restored as a `SerializedTrigger`, which is what the `TriggerInterface` normalizer already did for the Symfony serializer. The payload keeps its shape, so messages queued before the upgrade still decode.

A follow-up on symfony/recipes, symfony/recipes#1573, sets `use_messenger_routing: true` in the recipe for 8.2, since new apps should start with the option on.

The documentation should cover: the option, its default and the 9.0 flip; that routing then applies to every scheduled message; how to keep a task inline; that a routed task needs a running consumer and gains retries and a failure transport; that the message arguments must be serializable; and that the scheduler events fire in the scheduler worker and again in the consumer, where the trigger arrives as a description only.

Commits
-------

32efccedf6d [FrameworkBundle][Messenger][Scheduler] Add framework.scheduler.use_messenger_routing
N
Nicolas Grekas committed
5945ec3b609ffd21609f7fb05ec033ca480b4a83