eventuous
eventuous copied to clipboard
Cannot use more than one gateway transformation
The method GatewayRegistrations.AddGateway<TSubscription, TSubscriptionOptions, TProducer, TProduceOptions, TTransform>
registers a GatewayHandler
in the SubscriptionBuilder
.
Since AddGateway
passes the GatewayHandler
to AddEventHandler
as an IEventHandler
, and AddEventHandler
tries to register the handler in the service collection as a singleton, this means that only the first GatewayHandler is registered in the service collection. As a result, the first GatewayHandler (and its transformation) is used for all gateway subscriptions.
https://github.com/Eventuous/eventuous/blob/ed2c62edfc6f4b3d1c02e176be2f8d7e6a42cd6c/src/Gateway/src/Eventuous.Gateway/Registrations/GatewayRegistrations.cs#L127-L157
https://github.com/Eventuous/eventuous/blob/ed2c62edfc6f4b3d1c02e176be2f8d7e6a42cd6c/src/Core/src/Eventuous.Subscriptions/Registrations/SubscriptionBuilder.cs#L47-L53
For example, if I register two gateway subscriptions:
services.AddGateway<StreamSubscription, StreamSubscriptionOptions, EventStoreProducer, EventStoreProduceOptions, SellOrderTransformation>("SellOrders", ...);
services.AddGateway<StreamSubscription, StreamSubscriptionOptions, EventStoreProducer, EventStoreProduceOptions, BuyOrderTransformation>("BuyOrders", ...);
then both subscriptions will use SellOrderTransformation.
Yeah, that can actually be fixed the same way as event handlers and checkpoint stores are attached to subscriptions. The problem is that gateways DI integration is way less comprehensive than DI stuff for subs as it took me weeks to figure things out there. It definitely worth spending time and figure better DI support for gateways as well.
Hi, any update on this? How do you use multiple gateways? Or do you use just a single gateway for all cases?
A quick workaround we use is to create a custom sub class of TProduceOptions
per subscription.
Can you post the complete code for those?
services.AddGateway<StreamSubscription, StreamSubscriptionOptions, EventStoreProducer, EventStoreProduceOptions, SellOrderTransformation>("SellOrders", ...);
services.AddGateway<StreamSubscription, StreamSubscriptionOptions, EventStoreProducer, EventStoreProduceOptions, BuyOrderTransformation>("BuyOrders", ...);
I managed to create a quick fix. It won't work with functions but it will work with transformer classes. Here's the registration function (it existed before):
public static IServiceCollection AddGateway<TSubscription, TSubscriptionOptions, TProducer, TProduceOptions, TTransform>(
this IServiceCollection services,
string subscriptionId,
Action<TSubscriptionOptions>? configureSubscription = null,
Action<SubscriptionBuilder<TSubscription, TSubscriptionOptions>>? configureBuilder = null,
bool awaitProduce = true
)
where TSubscription : EventSubscription<TSubscriptionOptions>
where TProducer : class, IEventProducer<TProduceOptions>
where TProduceOptions : class
where TTransform : class, IGatewayTransform<TProduceOptions>
where TSubscriptionOptions : SubscriptionOptions
I will create a PR to support multiple transformers there, but it still has limitations. For example, the same transformer can't be used in more than gateway as the registration function I mentioned above adds a singleton GatewayHandler<TTransform, TProduceOptions>
so they must be unique with generic constraints to avoid the same issue.
I need to add a test to the PR before I merge it.
I also think that the registration code for subscriptions can be simplified further as most of the complexity there is to overcome missing keyed dependencies, but this is now solved.
Ok, I managed to change the registration code to use keyed dependencies. It's all a bit simpler now and handlers are completely independent. So, everything should work: functions, classes, whatever.