giudicelli/symfony-distributed-architecture
A Symfony package by Giudicelli for building distributed architectures, offering structure and integrations to help organize decoupled, scalable Symfony applications across multiple services.
Before you composer require anything, read the repo. With zero stars and zero dependents this is effectively an unreleased/experimental package. Pull it into a scratch project first:
composer require giudicelli/symfony-distributed-architecture --dev
Then run the three commands that tell you almost everything about a Symfony bundle:
composer show giudicelli/symfony-distributed-architecture # version constraints, deps
bin/console debug:config giudicelli_distributed_architecture # config tree + defaults
bin/console debug:container --tag=kernel.event_subscriber # what it auto-registers
Where to look first, in order:
composer.json — the symfony/* and php constraints are your compatibility gate. If it targets Symfony 4/5 and you're on 6/7, expect work.src/DependencyInjection/*Extension.php and Resources/config/*.yaml — the config tree plus service definitions reveal the actual API surface faster than any README.tests/ — for a package like this, the tests are the documentation. Grep for KernelTestCase / WebTestCase to see how it's meant to be booted.README.md — treat as a sketch, not a contract.Register the bundle if it isn't auto-discovered:
// config/bundles.php
return [
// ...
Giudicelli\SymfonyDistributedArchitecture\SymfonyDistributedArchitectureBundle::class => ['all' => true],
];
First use case: wire up a single happy-path message flow between two local services (producer → broker → consumer) in the dev environment with a synchronous or in-memory transport. Do not start with multi-service fan-out. Prove the bundle boots, the config key validates, and one message round-trips. Only then start layering environments and real transports.
Treat the bundle as infrastructure glue, not as your domain layer. The patterns that age well:
Contract-first message DTOs. Define your messages/events as plain immutable PHP classes in a shared src/Message/ namespace (or a shared composer package if you have multiple apps). Don't let the bundle's own classes leak into your domain — otherwise a package swap becomes a rewrite.
Configuration per environment, not per service. Typical shape:
# config/packages/distributed_architecture.yaml
when@dev:
giudicelli_distributed_architecture:
transport: in_memory # or sync — whatever the bundle exposes
when@prod:
giudicelli_distributed_architecture:
transport: amqp
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
If the bundle wraps Symfony Messenger (most of these do), keep the bundle config thin and push routing/serialization into config/packages/messenger.yaml where you already have tooling and docs.
Composition over inheritance. Use the bundle's interfaces/services as collaborators injected into your own application services. You want your handlers to be testable with a mock of the port, not with the bundle kernel booted.
Local development loop. Stand up the broker in docker-compose.yml (RabbitMQ/Redis) and run bin/console messenger:consume in a separate terminal. For debugging, prefer a sync transport in test so your functional tests don't need a broker.
Testing. Isolate the transport behind an interface and assert on the message, not the bus:
public function testOrderPlacedPublishesEvent(): void
{
$bus = $this->createMock(MessageBusInterface::class);
$bus->expects($this->once())->method('dispatch')
->with($this->isInstanceOf(OrderPlaced::class));
(new PlaceOrderHandler($bus))->__invoke(new PlaceOrder('123'));
}
Integration-test the real wiring once, in a dedicated test that boots the kernel — not in every unit test.
Multi-service integration tip: version your message schemas. Add a schemaVersion field to every event DTO from day one. Distributed systems break on deserialization long before they break on logic.
Adoption risk is the headline gotcha. Zero stars, zero dependents, score 0 means: no community to answer questions, no guarantee of maintenance, no security advisory feed. Before this touches production, either (a) fork it into your own VCS and pin the fork, or (b) restrict it to require-dev and prove you can replace it. Check the commit history — a single initial commit is a different proposition from steady maintenance.
No docs means the config tree is the docs. debug:config with no arguments prints the reference. Run it in every environment; extension classes often register different defaults per env, and a key that validates in dev can silently differ in prod.
Bundle auto-configuration is invisible. Services tagged kernel.event_subscriber or messenger.message_handler inside the bundle get registered without you seeing them. If you're seeing duplicate message handling, check debug:container --tag before you debug your own handlers.
Serialization drift. If the bundle serializes messages (PHP serialize() vs JSON), a class rename or added required constructor arg will break in-flight messages. Prefer JSON + explicit serializer if available, and never rename a message class without a migration path for the queue.
Idempotency and retries. Distributed flows retry. Make handlers idempotent (dedupe key, upsert, or an outbox) before you add a broker. Also configure a failure transport / DLQ — messenger:failed:show and messenger:failed:retry are your incident-response tools. If the bundle doesn't expose this, wrap it with Messenger's own.
Debugging slow or stuck flows:
bin/console debug:event-dispatcher # who listens to what
bin/console messenger:failed:show # dead-lettered messages
bin/console messenger:stats # queue depth per transport
Then enable TRACE-level logs on the bundle's namespace only — logging the whole container at debug level will drown you in Doctrine noise.
Extension points to look for (and to prefer over monkey-patching): compiler passes, tagged locators, and decorators. If the bundle registers a concrete MessageBus service, decorate it rather than overriding the service definition — decoration survives upgrades, redefinition doesn't.
Version pinning. Because there's no release cadence to rely on, pin an exact version or a VCS branch ("giudicelli/...": "dev-main#abcdef") in composer.json. Floating constraints on an unmaintained package are how you get a broken build on a Friday afternoon.
How can I help you explore Laravel packages today?