Event Throttle
Event Throttle
Section titled “Event Throttle”When publishing events rapidly (e.g. button clicks, form submissions, navigation triggers), you often want to act on the first event immediately but ignore subsequent duplicates for a cooldown period. The [Throttle] attribute implements this true throttle pattern — the first event executes right away, then all further events within the cooldown window are discarded.
This is particularly useful for scenarios like:
- Button clicks — prevent double-submit by executing the first click and ignoring rapid follow-ups
- Navigation events — act on the first trigger immediately, ignore duplicates
- API calls — fire the first request instantly, suppress bursts
-
Register the throttle event middleware in your host startup:
services.AddShinyMediator(cfg => cfg.AddThrottleEventMiddleware()); -
Mark your event handler method with the
[Throttle]attribute. The handler class must bepartial:[MediatorSingleton]public partial class ButtonClickHandler : IEventHandler<ButtonClickedEvent>{[Throttle(1000)] // 1000 milliseconds cooldownpublic async Task Handle(ButtonClickedEvent @event, IMediatorContext context, CancellationToken ct){// Executes immediately on first event.// All events within the next 1000ms are discarded.await ProcessClick();}}
How It Works
Section titled “How It Works”When an event is published and the handler has a [Throttle] attribute:
- If no cooldown is active, the handler executes immediately and a cooldown timer starts
- Any events published during the cooldown period are discarded
- Once the cooldown expires, the next event will execute immediately again (back to step 1)
This means the first event in a burst always runs instantly, and duplicates are suppressed until the cooldown passes.
Example — Preventing Double-Click
Section titled “Example — Preventing Double-Click”public record SubmitOrderEvent(int OrderId) : IEvent;
[MediatorSingleton]public partial class SubmitOrderHandler : IEventHandler<SubmitOrderEvent>{ readonly IOrderService orderService;
public SubmitOrderHandler(IOrderService orderService) { this.orderService = orderService; }
[Throttle(2000)] // 2 second cooldown after submission public async Task Handle(SubmitOrderEvent @event, IMediatorContext context, CancellationToken ct) { await this.orderService.Submit(@event.OrderId, ct); }}If the throttle delay is set to 0 or less, the middleware will execute the handler immediately without any throttling.