public When_using_EntityFrameworkConcurrencyFail() { _sagaDbContextFactory = new DelegateSagaDbContextFactory <ChoirStateOptimistic>( () => new SagaDbContext <ChoirStateOptimistic, EntityFrameworkChoirStateMap>(SagaDbContextFactoryProvider.GetLocalDbConnectionString())); _repository = new Lazy <ISagaRepository <ChoirStateOptimistic> >(() => EntityFrameworkSagaRepository <ChoirStateOptimistic> .CreateOptimistic(_sagaDbContextFactory)); }
public static void ConfigureBus(HostBuilderContext context, IServiceCollection services) { services.AddMassTransit(config => { config.AddBus(provider => Bus.Factory.CreateUsingRabbitMq(cfg => { var busConfig = context.Configuration.GetSection("Bus"); var host = cfg.ConfigureHost(busConfig); var connectionString = provider.GetRequiredService <IConfiguration>()["SagaStoreConnection"]; var optionsBuilder = new DbContextOptionsBuilder <SagaDbContext <SagaInstance, SagaInstanceMap> >(); optionsBuilder.UseSqlServer(connectionString, options => options.CommandTimeout(5)); DbContext contextFactory() => new SagaDbContext <SagaInstance, SagaInstanceMap>(optionsBuilder.Options); var repository = EntityFrameworkSagaRepository <SagaInstance> .CreateOptimistic(contextFactory); cfg.ReceiveEndpoint(host, "OrderWorkflow", e => { e.UseRetry(x => { x.Handle <DbUpdateConcurrencyException>(); // This is the SQLServer error code for duplicate key, if you are using another Relational Db, the code might be different x.Handle <DbUpdateException>(y => y.InnerException is SqlException ex && ex.Number == 2627); x.Interval(5, TimeSpan.FromMilliseconds(100)); }); e.UseFilter(new OperationContextFilter()); e.StateMachineSaga(new OrderSaga(provider.GetRequiredService <ILogger <OrderSaga> >()), repository); }); EndpointConvention.Map <CompleteOrder>(new Uri(new Uri(busConfig["Host"]), nameof(CompleteOrder))); EndpointConvention.Map <FailOrder>(new Uri(new Uri(busConfig["Host"]), nameof(FailOrder))); EndpointConvention.Map <Delivery.Commands.PlaceOrder>(new Uri(new Uri(busConfig["Host"]), "CreateDelivery")); contextFactory().Database.EnsureCreated(); })); }); services.AddSingleton <IHostedService, BusService>(); }
public static void AddMassTransitWithRabbitMq(this IServiceCollection services, IConfiguration appConfig) { if (services == null) { throw new ArgumentNullException("services"); } if (appConfig == null) { throw new ArgumentNullException("appConfig"); } var cfgSection = appConfig.GetSection("RabbitMqHost"); if (!cfgSection.Exists()) { throw new InvalidOperationException("Appsettings: 'RabbitMqHost' section is not found"); } services.Configure <RabbitMqHostOptions>(cfgSection); var epSection = appConfig.GetSection("MqEndpoints"); if (!epSection.Exists()) { throw new InvalidOperationException("Appsettings: 'MqEndpoints' section was not found"); } services.Configure <MqEndpointOptions>(epSection); services.AddMassTransit(cfg => { cfg.AddConsumer <RoutingSlipMetricsConsumer>(); cfg.AddConsumer <RoutingSlipActivityConsumer>(); cfg.AddSaga <RoutingSlipState>(); }); services.AddSingleton <RoutingSlipStateMachine>(); services.AddSingleton(svcProv => { var fact = svcProv.GetService <ILoggerFactory>(); return(new RoutingSlipMetrics("Routing Slip", fact.CreateLogger <RoutingSlipMetrics>())); }); services.AddSingleton <ValidateActivityMatrics>(); services.AddScoped <RoutingSlipMetricsConsumer>(svcProv => { var metrics = svcProv.GetService <RoutingSlipMetrics>(); return(new RoutingSlipMetricsConsumer(metrics)); }); services.AddScoped(svcProv => { var metrics = svcProv.GetService <ValidateActivityMatrics>(); var epOpts = svcProv.GetService <IOptions <MqEndpointOptions> >().Value; return(new RoutingSlipActivityConsumer(metrics, epOpts.ActivityMetrics.ActivityName)); }); services.AddSingleton(svcProv => { var config = svcProv.GetService <IConfiguration>(); var conStr = config.GetConnectionString("EfCoreRoutingSlip"); return(new RoutingSlipDbContextFactory(conStr)); }); services.AddSingleton <ISagaRepository <RoutingSlipState>, EntityFrameworkSagaRepository <RoutingSlipState> >(svcProv => { var ctxFactory = svcProv.GetService <RoutingSlipDbContextFactory>(); return(EntityFrameworkSagaRepository <RoutingSlipState> .CreateOptimistic(() => ctxFactory.CreateDbContext(Array.Empty <string>()))); }); services.AddSingleton(svcProv => { var hostOpts = svcProv.GetService <IOptions <RabbitMqHostOptions> >().Value; var epOpts = svcProv.GetService <IOptions <MqEndpointOptions> >().Value; var machine = svcProv.GetService <RoutingSlipStateMachine>(); var repository = svcProv.GetService <ISagaRepository <RoutingSlipState> >(); return(Bus.Factory.CreateUsingRabbitMq(cfg => { var host = cfg.CreateHost(hostOpts); cfg.ReceiveEndpoint(host, epOpts.Metrics.QueueName, e => { e.PrefetchCount = epOpts.Metrics.PrefetchCount; e.UseRetry(r => r.None()); //e.LoadFrom(svcProv); e.Consumer <RoutingSlipMetricsConsumer>(svcProv); e.Consumer <RoutingSlipActivityConsumer>(svcProv); }); cfg.ReceiveEndpoint(host, epOpts.ActivityMetrics.QueueName, e => { e.PrefetchCount = epOpts.ActivityMetrics.PrefetchCount; e.UseRetry(r => r.None()); }); cfg.ReceiveEndpoint(host, epOpts.Saga.QueueName, e => { e.UseInMemoryOutbox(); e.PrefetchCount = 1; e.UseConcurrencyLimit(1); e.StateMachineSaga(machine, repository); }); cfg.UseSerilog(); })); }); }