Skip to main content
The BeforeEventsDispatch handler is a custom module hook that allows you to intercept and process a batch of events received from supported message providers before it is dispatched to GraphQL subscription clients. Unlike OnReceiveEvents, this handler runs once per batch, before the batch is fanned out to any subscriber. This handler is particularly useful for:
  • Event filtering: Remove unwanted events before they reach any subscriber
  • Data transformation: Modify event payloads to match client expectations
  • Event enrichment: Add additional data to events from external sources
  • Monitoring and analytics: Log or track events for observability
This handler is very similar to the OnReceiveEvents but in contrast only runs once per batch, whereas the OnReceiveEvents handler runs for each active subscriber.
This comes with a trade-off. Event processing with this handler is much more lightweight because on a Router with 1000 subscribers this handler runs once instead of 1000 times. The downside is that you can’t do per-subscriber decisions in this hook. For that you need to use the OnReceiveEvents handler. A rule of thumb is to use this hook when you want to change the event for every client the same way.
If there is no active subscription this handler is not executed, even if new messages arrive at the provider. This is because the Router will not listen for messages on the provider topic/queue until at least one client subscribes to a particular subscription.

Handler Interface

In order to use the BeforeEventsDispatch handler you need to create a Custom Module which implements the StreamBeforeEventsDispatchHandler interface.

Execution Order and Performance Considerations

BeforeEventsDispatch runs before OnReceiveEvents. The router calls it once for the whole batch as soon as it is received from the provider, and only afterwards fans the (possibly modified) batch out to each active subscriber’s OnReceiveEvents handler. If you register multiple modules implementing BeforeEventsDispatch, they are executed sequentially, with each handler receiving the events returned by the previous one. Because this handler runs once per batch instead of once per subscriber, there is no max_concurrent_handlers option to configure. You can, however, configure how long the router waits for the handler(s) to finish before giving up on the batch:
If the timeout is reached, or the handler returns an error, the entire batch is dropped: it is never dispatched to any subscriber, and OnReceiveEvents does not run for that batch. A warning is logged in both cases. It is recommended to use ctx.Context(), which is cancelled in such situations. You can use this context to abort any long-running operations:
Unlike OnReceiveEvents, which only closes the subscription of the client that encountered the error, BeforeEventsDispatch failures drop the batch for every subscriber of that subscription, since the handler runs once for the shared batch rather than per client.

Error Handling

When the BeforeEventsDispatch handler returns an error, the router takes the following actions:
  1. Batch Dropped: The entire batch of events is discarded and never delivered to any subscriber
  2. No Subscription Closure: Unlike OnReceiveEvents, subscriptions stay open; the router simply waits for the next batch from the provider
  3. Error Logging: The error is logged by the router with details about the provider and field name
  4. No Error Propagation: The error is not sent to any GraphQL client
Returning an error from BeforeEventsDispatch drops the batch for all subscribers of the affected subscription. For filtering events, return an empty event list instead of an error so that other, unrelated batches keep flowing normally.
Example of proper error handling:

Usage Example

Complete Custom Module with Event Bypass

The following example contains a complete Custom Module implementation, including handler registration, with a handler that will simply bypass events unchanged. This is not useful on it’s own but demonstrates how to register your BeforeEventsDispatch Custom Module.

Restrict Handler to run on certain subscriptions and providers

Most of the time you want your hook to only deal with a certain subscription. The BeforeEventsDispatch Handler is run for every subscription configured for Cosmo Streams. You can access the name of the subscription you care for and return early if it’s not the right one.

Filter out events based on message metadata

Certain providers enrich their messages with metadata accessible by the Router. Kafka and NATS, for example, have the option to add headers to messages. Here’s an example that filters out all messages coming from a Kafka instance where a header indicates it’s not meant for GraphQL subscriptions. Since this handler runs once per batch, the filtering applies to every subscriber of the subscription at once.

Transform events

You can change event data. For example you could change the id of the entity you want to resolve for a client. Since this handler runs once per batch, the transformation applies to every subscriber of the subscription at once.