Replies: 2 comments 1 reply
-
|
Thank you so much for taking the time to thoughtfully outline these improvement ideas! 🙏 Your analysis is excellent, and I appreciate the depth of consideration you've put into each proposal. It's clear you have production experience with event-driven systems, and your suggestions directly address real-world challenges. I want to be transparent: the library is currently undergoing major architectural changes with the extension and changes of partitioning support. This is foundational work that needs to stabilize before layering these additional features on top.
Once this is solid, these feature proposals become much easier to implement cleanly. I'd love to implement these features! Even though I'm not in a position to accept contributions on these specific features right now, I want you to know:
Thank you again for the thoughtful contribution. This is exactly the kind of feedback that helps guide a library's evolution. I'm genuinely excited about implementing these features once I've solidified the foundation. |
Beta Was this translation helpful? Give feedback.
-
|
Over the past months, we reviewed each item and, in several cases, implemented a handler-oriented version of the proposal. Below is a final status update for each point. 1) First-Attempt Online Delivery (immediate publishing / post-commit emission)Status: Not supported (intentionally). We did consider an “emit immediately after transaction commit” path, but decided to keep the system strictly polling-driven. Why: the current model is partition-owned and non-competitive:
This keeps processing simple and efficient (select + update, no distributed locks, predictable behavior). Adding immediate delivery would introduce a second concurrent consumer (the post-commit async emitter) competing with the polling scheduler. Avoiding double processing would require additional “ownership/locking” mechanics (e.g., optimistic lock update, timeout management, extra DB round trips, edge cases around crashes and timeouts). Given that polling latency can be tuned and the current model is clean and scalable, we chose not to add this complexity at this time. 2) Retry Configuration per Event TypeStatus: Supported, but handler-oriented (not event-type-oriented). Instead of configuring retries “per event type”, the design is centered around the handler that processes a payload. This provides similar flexibility while keeping configuration close to the execution point. Example: @Component
class PaymentHandler {
@OutboxHandler
@OutboxRetryable(AggressiveRetryPolicy::class)
fun handlePayment(payload: PaymentEvent) {
paymentGateway.process(payload)
}
}3) Ordered vs. Non-Ordered Event TypesStatus: Supported. Ordering is enforced by the Ordered: outbox.schedule(
payload = OrderCreatedEvent(order.id, order.customerId),
key = "order-${order.id}"
)Non-ordered: outbox.schedule(
payload = OrderCreatedEvent(order.id, order.customerId),
)4) Trace PropagationStatus: Partially supported (context propagation supported; restoration is user-controlled). The library supports capturing and propagating “context” across the async boundary (e.g., trace IDs, correlation IDs, tenant/user metadata). Context capture is supported via a custom 5) Customizable Table Name PrefixStatus: Supported (JDBC module). A configurable table prefix is available via: 6) Task Executor per Event TypeStatus: Not supported. The processing model is polling-based and designed so that each poll cycle completes before the next begins. For this reason, processing runs on a single executor to preserve the scheduler’s sequencing and operational predictability. Per-event/handler executors were not added. 7) Retryable / Non-Retryable Exceptions per Event TypeStatus: Supported, but handler-oriented. Rather than being event-type-based, retryability is configured via the handler’s retry policy. Users can define which exceptions are retryable vs. fail-fast in the policy used by Closing this discussion since each item has been evaluated and either implemented (sometimes with a handler-based shape) or intentionally deferred to keep the core polling/partition design simple and robust. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
First, I want to express my appreciation for the work you’ve done. You’ve built an excellent Spring Boot library for implementing the transactional outbox pattern, and it already covers many critical features for production-grade systems, including:
I understand the library is still evolving, so I’d like to share a few improvement ideas that may be useful.
1. First-Attempt Online Delivery
It would be beneficial if the library attempted to send an event immediately after the transaction commits, using a background thread.
Benefits:
Key requirements:
2. Retry Configuration per Event Type
Different event types often have different delivery characteristics (e.g., HTTP POST calls to external services with varying response times).
Allowing retry policy configuration per event type, similar to how Resilience4j handles configs, would give users much finer control.
This could be implemented using Spring Boot properties.
3. Ordered vs. Non-Ordered Event Types
In many systems, some events must follow strict ordering, while others do not. Supporting both patterns would make the library more flexible.
One approach to achieve it:
order_datecolumn.order_date = created_at.order_date = null.4. Trace Propagation
It would be valuable for the library to automatically propagate tracing information (e.g.,
traceId) similarly to how Spring Boot and Micrometer handle it.Ideas:
This feature greatly improves cross-service observability.
5. Customizable Table Name Prefix
Some teams use a shared database across multiple services (e.g., “distributed monolith”), and rely on table prefixes such as
APP_X_orAPP_Y_to avoid collisions.It would be helpful if the library allowed specifying a prefix for all outbox tables, similar to how Quartz supports table prefix configuration.
6. Task Executor per Event Type
Spring supports executor selection for
@Asyncvia qualifiers.Adding a similar capability to the outbox, letting different event types use different executors, would improve performance tuning and isolation, especially in high-throughput systems.
7. Retryable / Non-Retryable Exceptions per Event Type
In some cases, certain exceptions should cause an event to fail immediately rather than be retried.
For example, if the application lacks permission to publish to a specific message queue, retrying will not resolve the issue.
To improve flexibility and reduce unnecessary retries, it would be useful to support:
If you'd like, I can help refine any of these ideas further or turn them into concrete design proposals or pull requests.
Beta Was this translation helpful? Give feedback.
All reactions