M12, M16 — build only the handler that runs, and stop making everything public - #280
Open
gplanchat wants to merge 1 commit into
Open
M12, M16 — build only the handler that runs, and stop making everything public#280gplanchat wants to merge 1 commit into
gplanchat wants to merge 1 commit into
Conversation
…ut rendre public
**Un gestionnaire d'activité appelé en construisait vingt.** `ActivityHandlerPass` posait
sur l'exécuteur des callables `[new Reference($invoker), '__invoke']`. Pour bâtir cet
argument, le conteneur doit résoudre chaque référence : il instanciait donc tous les
gestionnaires de l'application — et leurs connexions, clients HTTP et autres dépendances —
pour en appeler un seul. Sur un worker qui traite une activité par message, c'est payé à
chaque message.
Un localisateur de services le remplace, par `ServiceLocatorTagPass::register()` : le
mécanisme amont pour « beaucoup de candidats, un seul appelé », celui qu'emploie
MessengerPass pour les gestionnaires de messages. `RegistryActivityExecutor` reçoit ce
localisateur en argument facultatif et garde `register()` : les hôtes qui n'ont pas de
conteneur à offrir — Laravel, Magento, les tests — continuent d'enregistrer directement,
et un enregistrement direct l'emporte sur le localisateur, ce qui laisse un test remplacer
un gestionnaire sans reconstruire le conteneur.
**Onze services internes passent en privé.** Les implémentations concrètes derrière un
alias — journal DBAL, catalogue Temporal — et les décorateurs de projection n'ont aucune
raison d'être tirés du conteneur : on les atteint par leur interface, qui reste publique
et autowirable et rend la même instance. Un service public échappe à l'inlining et à
`RemoveUnusedDefinitionsPass`, et devient une promesse de compatibilité que personne n'a
voulu prendre.
Ce lot ne touche pas les 37 autres publics. Les workers Temporal, le magasin de liens
parent/enfant et le collecteur de profil sont tirés du conteneur par des tests du dépôt et
du banc ; les classes du moteur demanderaient un relevé des trois hôtes que je ne peux pas
exécuter ici. Restreindre ce qu'on a vérifié vaut mieux que privatiser au jugé.
Vérifié au-delà des tests unitaires : la suite d'intégration qui démarre un vrai noyau
passe, y compris son `$container->get('durable.child_workflow_parent_link_store')`.
Suite unit : 1087 tests contre 1073 sur main, mêmes 4 erreurs d'environnement. PHPStan :
2 erreurs, la base de main.
Refs: M12 et M16 de documentation/audit/
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two container-hygiene findings from the audit. Both are in
DurableExtensionandActivityHandlerPass.M16 — running one activity built every handler
ActivityHandlerPassregistered handlers on the executor as callables:To build that argument, the container has to resolve every
Reference. So it instantiated every activity handler in the application — and their connections, HTTP clients and whatever else they inject — in order to call one. It does not show in development, where handlers are light. It shows on a worker that processes one activity per message, with twenty contracts declared.A service locator replaces it, via
ServiceLocatorTagPass::register()— the upstream mechanism for "many candidates, one called", the same oneMessengerPassuses for message handlers.RegistryActivityExecutortakes the locator as an optional argument and keepsregister(). Hosts with no service container to offer — Laravel, Magento, the test helpers — keep registering directly. A direct registration wins over the locator, so a test can replace one handler without rebuilding the container.The test counts real instantiations: getting the executor builds zero handlers, and executing
premier.fairebuilds exactly one.M12 — eleven internal services become private
Concrete implementations behind an alias — the DBAL journal, the Temporal catalogue — and the projection decorators have no reason to be container entry points. You reach them through their interface, which stays public and autowirable and returns the same instance.
A public service escapes inlining and
RemoveUnusedDefinitionsPass, and becomes a compatibility promise nobody meant to make.durable.event_store.dbal,.temporal,.inner,.*.projectingEventStoreInterfacedurable.workflow_metadata_store.inner,.*.projectingWorkflowMetadataStoredurable.run_catalog.dbal,.in_memory,.temporalWorkflowRunCatalogInterfaceWhat this deliberately leaves alone
The audit counts 48 public services. This changes 11. The other 37 stay, and the reason is not laziness:
durable.temporal.activity_worker,durable.temporal.nexus_workeranddurable.child_workflow_parent_link_storeare fetched by id from a real container in this repository's and the sample app's tests.DurableDataCollector,EventStoreInterface,WorkflowMetadataStoreandWorkflowResumeDispatcherare what the shippedDurableBundleTestTraitresolves — that is the documented public surface.Narrowing what has been verified beats privatising on a hunch: a wrong call here breaks a consumer at runtime.
Breaking change
Behavioural, for an application that fetches one of those eleven ids with
$container->get().UPGRADE.mdcarries the mapping table and says why Rector cannot help — rewriting aget()into an injection needs to know where the object is used, which no rule can guess.Verification
mainunitsuiteintegrationsuiteThe four errors are pre-existing and identical (
illuminate/cacheis not installed on this machine).Beyond the unit suite: the integration test that boots a real kernel passes, including its
$container->get('durable.child_workflow_parent_link_store')— which is the check that matters for a change to service visibility.