keboola/messenger-bundle
A Symfony bundle that integrates Keboola Messenger into PHP applications, wiring its messaging services into the Symfony container and simplifying configuration for sending and handling messages in projects that use Keboola’s messaging components.
Architecture fit. This is a Symfony bundle, not a Laravel package, and that distinction dominates the evaluation. It ships a DependencyInjection\KeboolaMessengerExtension that does its work in prependExtension(), injecting framework.messenger transport configuration before FrameworkBundle compiles the container. There is no service provider, no config/*.php publishable config, and no Laravel contract binding. In a Laravel application the bundle is effectively inert: Laravel does not run Symfony's prependExtension()/Extension lifecycle, so none of the transport wiring, serializer selection, or transport-factory decoration will occur. The underlying value — platform-specific envelope deserializers, typed event factories, and the GPS transport decorator — is real, but it is delivered through a Symfony-only integration seam.
Integration feasibility. Low for direct installation; moderate for pattern reuse. Three plausible paths exist: (1) run a Symfony service alongside the Laravel app and share the queue, (2) port the serializers and factories into Laravel-native consumers, (3) adopt the package only if the organization is already on Symfony. The serializers themselves are the most portable asset — each unwraps a cloud-specific envelope (SNS/SQS body, Event Grid, Pub/Sub) and hands a payload to AuditEventFactory / ApplicationEventFactory. If those classes are framework-light, they can be consumed standalone; if they resolve collaborators from the container, they cannot. That is the single most important unknown to resolve before committing.
Technical risk. Several items warrant scrutiny:
keboola/platform-libraries under libs/messenger-bundle/, with Conventional Commits scoped as fix(messenger-bundle): …. This is a viable but non-obvious contribution path that constrains your ability to carry local patches.EventInterface, falling back to GenericAuditLogEvent / GenericApplicationEvent on unknown names. Upgrading can silently promote an event from generic to typed, which is a breaking change for any handler that matches on type. This is a latent upgrade hazard, not a startup hazard.GpsTransportFactoryDecorator now applies the default 120s REST / 10s connect timeout to all gps:// transports, not just those it previously touched. Transports that were effectively unbounded now cap at 120s. The stated motive is to stop Pub/Sub consumers hanging indefinitely on half-open connections during long-poll pulls — a real bug — but it means upgrade-time behavior changes for any consumer that depended on the absence of a timeout, and it confirms the maintainers treat these defaults as their tuning surface. Expect further default adjustments in minor releases; pin versions and re-read this decorator on every upgrade.Key questions.
Serializer\* and the two event factories free of Symfony container dependencies, so they can be instantiated directly?Platform enum approach (aws/azure/gcp) match our actual cloud topology, or would we need a new case, serializer, and extension branch?client_config (in options or DSN) to opt out, because 3.4.0 leaves explicitly-configured transports untouched and does not merge partial config with the defaults.Stack fit. The package presumes PHP 8.2, Symfony FrameworkBundle with Messenger enabled, and platform resolvable at container-build time. It explicitly resolves env placeholders during prependExtension() (resolveEnvPlaceholders(..., true)), which means the platform cannot be chosen dynamically at runtime — it is a build-time decision baked into the compiled container. For a Laravel stack, the honest assessment is that this is a reference implementation, not a dependency.
Migration path. Recommended sequencing for a Laravel team:
AwsSqsSerializer (or the relevant platform serializer) plus the event factories outside a Symfony container. Time-box this to days. The outcome determines everything downstream.prependExtension() mechanism has no Laravel analogue. Configure queue connections through config/queue.php and replicate the intent (platform selection, per-platform serializer binding, timeout defaults) explicitly. The 3.4.0 GPS timeout work is a concrete example of something you will be hand-porting rather than inheriting.platform in bundle config, and rely on the supported "bundle installed but inactive" state — when platform is unset the extension returns early and registers no transport — for staged rollout.Compatibility. PHP 8.2 is the tested baseline via the dev-messenger-bundle Docker service with APP_ENV=dev. Note the non-standard build convention: PHPStan config is selected by APP_ENV (phpstan analyse -c phpstan-${APP_ENV}.neon), and composer ci runs php tests/bootstrap.php first to warm the test kernel. A stale var/ cache is the documented cause of confusing DI failures. If you fork or vendor, replicate these conventions or your first debugging session will be spent on tooling.
Sequencing. Do not parallelize the spike with infrastructure provisioning. The queue-consumption tests (tests/ConnectionEvent/{AwsSqs,AzureServiceBus,GooglePubSub}ConsumptionTest.php) require real cloud queues provisioned through the Terraform setup in provisioning/; the rest of the suite runs offline. Establish whether you are willing to stand up that provisioning story before you commit engineering time, because without it you have unit coverage of serialization only and no confidence in end-to-end behavior. The 3.4.0 fix is specifically about long-poll behavior over real connections — the class of bug a mocked suite will not catch — which raises the value of that provisioning work.
Maintenance. The maintenance model is the primary operational concern. The library is a monorepo artifact mirrored for Composer; you cannot patch it in place. Every fix requires a contribution to keboola/platform-libraries, review by Keboola's team, a monorepo release tag, and mirror regeneration. Budget for this as a standing dependency relationship rather than a normal open-source contribution loop. If Keboola is a commercial partner, formalize it; if not, assume indefinite latency on fixes and design a local workaround layer.
Support. No community to lean on — zero dependents means no field reports, no third-party answers, no prior art. First-line support is your own team reading the source, and second-line is a Keboola maintainer whose primary obligation is the internal platform. The AGENTS.md files are unusually good for an internal library and materially reduce ramp-up cost, but they are contributor documentation, not consumer documentation.
Scaling. The design scales reasonably with queue volume because it is stateless deserialization plus factory dispatch. Two scaling caveats remain, and 3.4.0 sharpens both. The GPS transport decorator's 120s REST / 10s connect defaults will hold worker slots for up to two minutes on a dead connection — that is now the guaranteed ceiling on every gps:// transport, not an opt-in. And setting client_config disables rather than merges the defaults, so custom tuning must restate every value in full. Size worker pools with the 120s worst case in mind, and treat the decorator as the single place where timeout policy lives.
Failure modes. The notable ones:
GenericAuditLogEvent/GenericApplicationEvent. This is deliberate and prevents consumer crashes, but it also means new event types can flow through untyped and be handled by a catch-all without anyone noticing. Instrument the fallback path with logging before go-live.platform is unset, the extension returns early and registers no transport. This is a supported state but an easy misconfiguration: the application boots cleanly and simply never consumes anything. Add a startup assertion.gps:// DSN and options block before upgrading, and explicitly declare client_config where the new ceiling is wrong.Ramp-up. The library is small and the AGENTS.md documentation is genuinely strong on architecture — the rationale for prependExtension(), the platform-as-only-switch design, factory-over-message-classes, and the GPS decorator are all explained. Expect low ramp-up for a Symfony-experienced engineer (days) and moderate for a Laravel-only team (weeks), because the conceptual model — container-time configuration, transport factories, envelope unwrapping per cloud — does not have a direct Laravel analogue and must be relearned rather than transferred. 3.4.0 is a good teaching example for that gap: a one-line-sounding default is a substantive production behavior change, and there is no Laravel-side equivalent to inherit it from.
How can I help you explore Laravel packages today?