rossel/rossel-kafka
rossel/rossel-kafka provides Kafka integration for Laravel and PHP applications, helping you configure producers and consumers, publish messages to topics, and process Kafka events using familiar Laravel conventions. Useful for event streaming and service-to-service messaging.
Architecture fit. The release notes materially correct the framing of the previous assessment: this is a Symfony bundle (composer type: symfony-bundle, AbstractBundle, config/bundles.php, Flex auto-registration), not a Laravel package. That splits the architectural question in two. First, unchanged: it is an opinionated facade over Rossel's broker topology, topic naming, auth, and serialization, valuable only where we have an obligation to that platform. Second, and new: it is only a fit for Symfony services. For a Laravel service, adopting it means either running a Symfony kernel alongside Laravel or stripping the bundle wrapper and consuming the underlying library directly — at which point the bundle is contributing almost nothing and we should evaluate the generic client instead. The package is still the wrong abstraction for any non-Rossel cluster.
Integration feasibility. Improved for Symfony, degraded for Laravel. Symfony 6.4 support and Flex registration make installation genuinely composer require-shaped in a Symfony app; the removal of RosselKafkaExtension, Configuration, and services.yaml in favour of AbstractBundle reduces boilerplate and removes a class of container-loading bugs. Two new gates: broker and producer config sections are now required, so a misconfigured container fails at build rather than with "Undefined array key" at runtime (a genuine improvement, but it means config is now load-bearing at deploy time). And the enqueue bundle is gone — if anything in our stack relied on it, we must self-configure. The non-code prerequisites are unchanged and still the real gate: broker reachability, credentials, ACLs, and a documented message envelope. A time-boxed spike with real credentials against a sandbox topic remains the only reliable feasibility test.
Technical risk. Maturity signals are unchanged — one star, one publishing organisation, bus factor of one, no external battle-testing. What has changed is evidence of active, serious maintenance: a documented migration guide (UPGRADE-0.7.md), semver-honest BC breaks, and fixes to real correctness bugs. That cuts both ways. It means we are not adopting an abandoned package; it also means we should expect further breaks before 1.0 and must budget for them. Specific risk deltas:
PLAIN when sasl_mechanism is unset, fixing a silent GSSAPI default — though a permissive fallback can also mask a missing config value, so verify the negotiated mechanism.rossel:kafka:listen; it is logged, acknowledged, and the listener moves on. This converts a poison message from a loud partition stall into a silent drop. Unless we alert on EXEC_ERROR and own our own retry/DLQ path, this trades an availability incident for a data-integrity incident.Key questions.
EXEC_SUCCESS/EXEC_ERROR — structured, correlatable, does it include topic/partition/offset/key? Is it safe to alert on?rossel_kafka.consumer tag to wrap consumer execution (for idempotency, metrics, tracing) given the extension class was removed?producer.send_log_messages: false remove observability we need, or only log noise?MessageHeadersInterface and RdKafkaMessageWrapperInterface leave a stable enough public surface to write against, or is it still in flux?Stack fit. The adapter recommendation from the previous assessment is now validated by evidence rather than caution: this release removed three public types and moved a method between interfaces. Any domain code that touched MessageHeadersInterface, RdKafkaMessageWrapperInterface, or UnsupportedTopicException would have broken on a minor bump. So the layering stands and is non-negotiable — our application publishes and consumes through internal EventPublisher/MessageConsumer interfaces, with a Rossel adapter as one implementation. Additionally, the adapter now absorbs a framework mismatch: for Symfony services it is thin; for Laravel services it is the only viable seam if we use the underlying library at all. Compare against mateusjunges/laravel-kafka or php-rdkafka directly, and note that the delta is now larger than a config file (lazy producer, post-processing commit, PLAIN fallback are real behaviours) but still not large enough to justify adopting a Symfony bundle inside Laravel.
Migration path. Still greenfield for us — we have not shipped against 0.6.x. Two practical consequences. First, pin exactly (0.7.0, not ^0.7) until we have read UPGRADE-0.7.md and decided a tracking policy; any spike code written against 0.6.x is now broken and should be discarded rather than patched. Second, the new delivery semantics must be designed in from the start, not retrofitted: every consumer needs an idempotency strategy (natural key, dedupe table, or upsert) because redelivery on restart is now guaranteed behaviour. Path: proof-of-concept command → adapter-wrapped integration in one non-critical consumer behind a flag → additional producers/consumers only after surviving one release cycle. Do not let Rossel types into shared libraries.
Compatibility. Verify: PHP constraint against runtime; Symfony 6.4+ and whether symfony/flex is present (manual bundles.php registration otherwise); ext-rdkafka/librdkafka versions across local Docker, CI, and production images; that our config file binds under the new AbstractBundle loading and includes both broker and producer sections; that EnqueueBundle is absent or deliberately self-configured; and that the serialization format matches what exists on Rossel's topics today. Note that lazy SSL means certificate and CA download failures now surface on first use — add a startup warm-up or health check rather than discovering it on the first message.
Sequencing.
UPGRADE-0.7.md in full.EXEC_ERROR alerting wired up.Maintenance. A pre-1.0 package shipping breaking minors with migration guides is maintainable but not free — budget upgrade work per minor version, and assume the 0.8 line breaks something again. The removal of the extension class and Configuration shrinks the surface we would have to carry if we fork, which makes forking marginally cheaper than assessed previously; the fork-or-pin decision should still be recorded explicitly at the end of the spike rather than drifted into as an unmaintained pin.
Support. Unchanged: support is a relationship with the Rossel platform team, not a community. One named contact, an escalation path for broker outages, and an expectation of notice on schema changes. The changelog being a single PR by a single author reinforces this — there is no queue of third-party issue reports to learn from.
Scaling. Throughput is still bounded by the underlying client (presumed ext-rdkafka) and our consumer worker topology. Two modest improvements: consumer-only pods no longer hold a producer, reducing connections and memory; and lazy SSL resolution removes boot-time dependency on a CA download, improving cold-start reliability. Watch for the trade-off — first-message latency now includes connection setup and certificate resolution, so a warm-up or readiness probe matters. Rebalancing behaviour, partition assignment, and backpressure still need to be observed under load, not inferred.
Failure modes. The list has changed meaningfully and the acceptance criteria must be rewritten:
EXEC_ERROR and a deliberate retry/DLQ path, poison messages become silent data loss with no backpressure signal. Treat "does an EXEC_ERROR page someone" as a go-live gate.PLAIN can mean we connect with a weaker or unintended mechanism. Assert the negotiated mechanism in the spike.broker/producer config now fails container build — fail-fast and preferable, but config becomes a deploy-time dependency to validate in CI.max.poll.interval handling; schema drift surfacing as deserialization drops; retry amplification from naive loops.Ramp-up. Engineer time is still dominated by learning Rossel's conventions rather than the API, and that knowledge lives in package source. Add the new semantics to the learning curve — idempotency design and failure-path ownership are now part of the integration, not optional polish. Assume one senior engineer for a week to a defensible spike conclusion for a Symfony service, plus reading the migration guide and writing internal integration notes. If more than one squad touches Kafka, the adapter layer is mandatory and the ramp-up cost multiplies.
Recommendation. Downgrade to conditional and stack-scoped. For a Symfony service with a concrete obligation to Rossel's Kafka platform, 0.7.0 is a materially better dependency than the version previously assessed — the offset-commit fix alone removes a data-loss class — and adoption through an internal adapter, pinned exactly, is defensible provided we own idempotency and an EXEC_ERROR-triggered failure path from day one. For a Laravel service, do not adopt the bundle; evaluate a generic client against the same Rossel conventions instead. Absent a platform obligation, the package still offers no reusable capability.
How can I help you explore Laravel packages today?