Problem
domain_source carries its own copy of core's route matching, in DomainSourceRouteMatcher and the domain_source.route_provider service behind it, so that the outbound path processor can learn the route behind a path. Its own docblock says the class stops being necessary once #3202329 is resolved. That issue is fixed and landed in 11.4, and 4.x requires ^11.4 || ^12.
Why it is no longer reachable with an answer core does not already have
UrlGenerator::generateFromRoute() now sets route, route_name and route_parameters, and DomainSourcePathProcessor already skips the matcher when route_name is set. An internal: URI is not an exception: Url::fromInternalUri() resolves it through PathValidator::getUrlIfValidWithoutAccessCheck(), which route matches the path including its alias and returns a routed Url. The matcher is therefore entered only for paths core could not route, and it uses the same router, so it cannot route them either.
Measured on core 12: 11 of 15 outbound calls in the domain_source functional tests already skip the matcher, and the 4 that enter it come from UnroutedUrlAssembler by way of BrowserTestBase::buildUrl(), which is the test harness. With the matcher disabled outright, the whole domain and domain_source suites pass, 151 tests and 2474 assertions.
This cannot be only a removal
DomainSourceRouteProvider is what carries the active domain in the route cache ID, which is #3623187. Removing it moves that resolution onto core's router.route_provider, which in a CLI process holds no domain key part at all, because DomainSubscriber registers it on KernelEvents::REQUEST only. A cron run that serves several domains would then resolve a shared alias once and reuse it for every later domain.
Proposed resolution
Remove DomainSourceRouteMatcher, DomainSourceRouteProvider, the domain_source.route_provider service, the block in DomainSourcePathProcessor::processOutbound() that calls the matcher, and their tests. In the same change, add the domain to core's router.route_provider cache ID where the ID is built, so that it follows the active domain in CLI as well as in a request.
A test covering a process that serves several domains in turn should land with it. The existing coverage asserts the cache ID and the route match, and none of it exercises the cron shape this turns on.
Remaining on the older branches
2.0.x, 3.0.x and 3.x support core below 11.4, where the path processor is not given the route, so the matcher stays there and #3623187 is fixed in place.
AI-Generated: Yes (Claude Code was used to help draft this issue summary and to run the measurements it cites. I reviewed them. The call site counts and the suite result come from instrumented runs against core 12, and the claim about internal: URIs was read from core's Url::fromInternalUri().)
Issue fork domain-3623227
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
mably commentedComment #5
mably commented