Send IntegrationEvents after committing transactions
This commit is contained in:
parent
adafb9abf4
commit
24bed0aa33
@ -217,14 +217,16 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
if (subscription.IsDynamic)
|
if (subscription.IsDynamic)
|
||||||
{
|
{
|
||||||
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
||||||
|
if (handler == null) continue;
|
||||||
dynamic eventData = JObject.Parse(message);
|
dynamic eventData = JObject.Parse(message);
|
||||||
await handler.Handle(eventData);
|
await handler.Handle(eventData);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var handler = scope.ResolveOptional(subscription.HandlerType);
|
||||||
|
if (handler == null) continue;
|
||||||
var eventType = _subsManager.GetEventTypeByName(eventName);
|
var eventType = _subsManager.GetEventTypeByName(eventName);
|
||||||
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
||||||
var handler = scope.ResolveOptional(subscription.HandlerType);
|
|
||||||
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
||||||
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
|
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
|
||||||
}
|
}
|
||||||
|
@ -163,14 +163,16 @@
|
|||||||
if (subscription.IsDynamic)
|
if (subscription.IsDynamic)
|
||||||
{
|
{
|
||||||
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
||||||
|
if (handler == null) continue;
|
||||||
dynamic eventData = JObject.Parse(message);
|
dynamic eventData = JObject.Parse(message);
|
||||||
await handler.Handle(eventData);
|
await handler.Handle(eventData);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var eventType = _subsManager.GetEventTypeByName(eventName);
|
|
||||||
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
|
||||||
var handler = scope.ResolveOptional(subscription.HandlerType);
|
var handler = scope.ResolveOptional(subscription.HandlerType);
|
||||||
|
if (handler == null) continue;
|
||||||
|
var eventType = _subsManager.GetEventTypeByName(eventName);
|
||||||
|
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
||||||
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
||||||
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
|
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
|
|||||||
public enum EventStateEnum
|
public enum EventStateEnum
|
||||||
{
|
{
|
||||||
NotPublished = 0,
|
NotPublished = 0,
|
||||||
Published = 1,
|
InProgress = 1,
|
||||||
PublishedFailed = 2
|
Published = 2,
|
||||||
|
PublishedFailed = 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using System.Linq;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
|
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
|
||||||
{
|
{
|
||||||
@ -11,7 +13,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
|
|||||||
private IntegrationEventLogEntry() { }
|
private IntegrationEventLogEntry() { }
|
||||||
public IntegrationEventLogEntry(IntegrationEvent @event)
|
public IntegrationEventLogEntry(IntegrationEvent @event)
|
||||||
{
|
{
|
||||||
EventId = @event.Id;
|
EventId = @event.Id;
|
||||||
CreationTime = @event.CreationDate;
|
CreationTime = @event.CreationDate;
|
||||||
EventTypeName = @event.GetType().FullName;
|
EventTypeName = @event.GetType().FullName;
|
||||||
Content = JsonConvert.SerializeObject(@event);
|
Content = JsonConvert.SerializeObject(@event);
|
||||||
@ -20,9 +22,18 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
|
|||||||
}
|
}
|
||||||
public Guid EventId { get; private set; }
|
public Guid EventId { get; private set; }
|
||||||
public string EventTypeName { get; private set; }
|
public string EventTypeName { get; private set; }
|
||||||
|
[NotMapped]
|
||||||
|
public string EventTypeShortName => EventTypeName.Split('.')?.Last();
|
||||||
|
[NotMapped]
|
||||||
|
public IntegrationEvent IntegrationEvent { get; private set; }
|
||||||
public EventStateEnum State { get; set; }
|
public EventStateEnum State { get; set; }
|
||||||
public int TimesSent { get; set; }
|
public int TimesSent { get; set; }
|
||||||
public DateTime CreationTime { get; private set; }
|
public DateTime CreationTime { get; private set; }
|
||||||
public string Content { get; private set; }
|
public string Content { get; private set; }
|
||||||
|
|
||||||
|
public void DeserializeJsonContent(Type type)
|
||||||
|
{
|
||||||
|
IntegrationEvent = JsonConvert.DeserializeObject(Content, type) as IntegrationEvent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,10 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Servi
|
|||||||
{
|
{
|
||||||
public interface IIntegrationEventLogService
|
public interface IIntegrationEventLogService
|
||||||
{
|
{
|
||||||
|
Task<IEnumerable<IntegrationEventLogEntry>> RetrieveEventLogsPendingToPublishAsync();
|
||||||
Task SaveEventAsync(IntegrationEvent @event, DbTransaction transaction);
|
Task SaveEventAsync(IntegrationEvent @event, DbTransaction transaction);
|
||||||
Task MarkEventAsPublishedAsync(IntegrationEvent @event);
|
Task MarkEventAsPublishedAsync(Guid eventId);
|
||||||
|
Task MarkEventAsInProgressAsync(Guid eventId);
|
||||||
|
Task MarkEventAsFailedAsync(Guid eventId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -10,12 +14,15 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Servi
|
|||||||
{
|
{
|
||||||
public class IntegrationEventLogService : IIntegrationEventLogService
|
public class IntegrationEventLogService : IIntegrationEventLogService
|
||||||
{
|
{
|
||||||
|
private readonly IEventBusSubscriptionsManager _subsManager;
|
||||||
private readonly IntegrationEventLogContext _integrationEventLogContext;
|
private readonly IntegrationEventLogContext _integrationEventLogContext;
|
||||||
private readonly DbConnection _dbConnection;
|
private readonly DbConnection _dbConnection;
|
||||||
|
|
||||||
public IntegrationEventLogService(DbConnection dbConnection)
|
public IntegrationEventLogService(IEventBusSubscriptionsManager subsManager,
|
||||||
|
DbConnection dbConnection)
|
||||||
{
|
{
|
||||||
_dbConnection = dbConnection ?? throw new ArgumentNullException(nameof(dbConnection));
|
_dbConnection = dbConnection ?? throw new ArgumentNullException(nameof(dbConnection));
|
||||||
|
_subsManager = subsManager ?? throw new ArgumentNullException(nameof(subsManager));
|
||||||
_integrationEventLogContext = new IntegrationEventLogContext(
|
_integrationEventLogContext = new IntegrationEventLogContext(
|
||||||
new DbContextOptionsBuilder<IntegrationEventLogContext>()
|
new DbContextOptionsBuilder<IntegrationEventLogContext>()
|
||||||
.UseSqlServer(_dbConnection)
|
.UseSqlServer(_dbConnection)
|
||||||
@ -23,6 +30,19 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Servi
|
|||||||
.Options);
|
.Options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<IntegrationEventLogEntry>> RetrieveEventLogsPendingToPublishAsync()
|
||||||
|
{
|
||||||
|
var eventLogsPendingToPublish = await _integrationEventLogContext.IntegrationEventLogs
|
||||||
|
.Where(e => e.State == EventStateEnum.NotPublished)
|
||||||
|
.OrderBy(o => o.CreationTime)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
eventLogsPendingToPublish.ForEach(evtLog =>
|
||||||
|
evtLog.DeserializeJsonContent(_subsManager.GetEventTypeByName(evtLog.EventTypeShortName)));
|
||||||
|
|
||||||
|
return eventLogsPendingToPublish;
|
||||||
|
}
|
||||||
|
|
||||||
public Task SaveEventAsync(IntegrationEvent @event, DbTransaction transaction)
|
public Task SaveEventAsync(IntegrationEvent @event, DbTransaction transaction)
|
||||||
{
|
{
|
||||||
if (transaction == null)
|
if (transaction == null)
|
||||||
@ -38,11 +58,28 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Servi
|
|||||||
return _integrationEventLogContext.SaveChangesAsync();
|
return _integrationEventLogContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task MarkEventAsPublishedAsync(IntegrationEvent @event)
|
public Task MarkEventAsPublishedAsync(Guid eventId)
|
||||||
{
|
{
|
||||||
var eventLogEntry = _integrationEventLogContext.IntegrationEventLogs.Single(ie => ie.EventId == @event.Id);
|
return UpdateEventStatus(eventId, EventStateEnum.Published);
|
||||||
eventLogEntry.TimesSent++;
|
}
|
||||||
eventLogEntry.State = EventStateEnum.Published;
|
|
||||||
|
public Task MarkEventAsInProgressAsync(Guid eventId)
|
||||||
|
{
|
||||||
|
return UpdateEventStatus(eventId, EventStateEnum.InProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task MarkEventAsFailedAsync(Guid eventId)
|
||||||
|
{
|
||||||
|
return UpdateEventStatus(eventId, EventStateEnum.PublishedFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UpdateEventStatus(Guid eventId, EventStateEnum status)
|
||||||
|
{
|
||||||
|
var eventLogEntry = _integrationEventLogContext.IntegrationEventLogs.Single(ie => ie.EventId == eventId);
|
||||||
|
eventLogEntry.State = status;
|
||||||
|
|
||||||
|
if(status == EventStateEnum.InProgress)
|
||||||
|
eventLogEntry.TimesSent++;
|
||||||
|
|
||||||
_integrationEventLogContext.IntegrationEventLogs.Update(eventLogEntry);
|
_integrationEventLogContext.IntegrationEventLogs.Update(eventLogEntry);
|
||||||
|
|
||||||
|
@ -29,9 +29,16 @@ namespace Catalog.API.IntegrationEvents
|
|||||||
|
|
||||||
public async Task PublishThroughEventBusAsync(IntegrationEvent evt)
|
public async Task PublishThroughEventBusAsync(IntegrationEvent evt)
|
||||||
{
|
{
|
||||||
_eventBus.Publish(evt);
|
try
|
||||||
|
{
|
||||||
await _eventLogService.MarkEventAsPublishedAsync(evt);
|
await _eventLogService.MarkEventAsInProgressAsync(evt.Id);
|
||||||
|
_eventBus.Publish(evt);
|
||||||
|
await _eventLogService.MarkEventAsPublishedAsync(evt.Id);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
await _eventLogService.MarkEventAsFailedAsync(evt.Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveEventAndCatalogContextChangesAsync(IntegrationEvent evt)
|
public async Task SaveEventAndCatalogContextChangesAsync(IntegrationEvent evt)
|
||||||
|
@ -232,7 +232,11 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
|||||||
public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
||||||
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
sp =>
|
||||||
|
{
|
||||||
|
var busMgr = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
return (DbConnection c) => new IntegrationEventLogService(busMgr, c);
|
||||||
|
});
|
||||||
|
|
||||||
services.AddTransient<ICatalogIntegrationEventService, CatalogIntegrationEventService>();
|
services.AddTransient<ICatalogIntegrationEventService, CatalogIntegrationEventService>();
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ordering.API.Application.IntegrationEvents;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -14,10 +15,14 @@ namespace Ordering.API.Application.Behaviors
|
|||||||
{
|
{
|
||||||
private readonly ILogger<TransactionBehaviour<TRequest, TResponse>> _logger;
|
private readonly ILogger<TransactionBehaviour<TRequest, TResponse>> _logger;
|
||||||
private readonly OrderingContext _dbContext;
|
private readonly OrderingContext _dbContext;
|
||||||
|
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
||||||
|
|
||||||
public TransactionBehaviour(OrderingContext dbContext, ILogger<TransactionBehaviour<TRequest, TResponse>> logger)
|
public TransactionBehaviour(OrderingContext dbContext,
|
||||||
|
IOrderingIntegrationEventService orderingIntegrationEventService,
|
||||||
|
ILogger<TransactionBehaviour<TRequest, TResponse>> logger)
|
||||||
{
|
{
|
||||||
_dbContext = dbContext ?? throw new ArgumentException(nameof(OrderingContext));
|
_dbContext = dbContext ?? throw new ArgumentException(nameof(OrderingContext));
|
||||||
|
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentException(nameof(orderingIntegrationEventService));
|
||||||
_logger = logger ?? throw new ArgumentException(nameof(ILogger));
|
_logger = logger ?? throw new ArgumentException(nameof(ILogger));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +44,8 @@ namespace Ordering.API.Application.Behaviors
|
|||||||
await _dbContext.CommitTransactionAsync();
|
await _dbContext.CommitTransactionAsync();
|
||||||
|
|
||||||
_logger.LogInformation($"Committed transaction {typeof(TRequest).Name}");
|
_logger.LogInformation($"Committed transaction {typeof(TRequest).Name}");
|
||||||
|
|
||||||
|
await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
||||||
{
|
{
|
||||||
using Domain.AggregatesModel.OrderAggregate;
|
using Domain.AggregatesModel.OrderAggregate;
|
||||||
|
using global::Ordering.API.Application.IntegrationEvents;
|
||||||
|
using global::Ordering.API.Application.IntegrationEvents.Events;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
@ -15,17 +17,26 @@
|
|||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
private readonly IIdentityService _identityService;
|
private readonly IIdentityService _identityService;
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
||||||
|
|
||||||
// Using DI to inject infrastructure persistence Repositories
|
// Using DI to inject infrastructure persistence Repositories
|
||||||
public CreateOrderCommandHandler(IMediator mediator, IOrderRepository orderRepository, IIdentityService identityService)
|
public CreateOrderCommandHandler(IMediator mediator,
|
||||||
|
IOrderingIntegrationEventService orderingIntegrationEventService,
|
||||||
|
IOrderRepository orderRepository,
|
||||||
|
IIdentityService identityService)
|
||||||
{
|
{
|
||||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
||||||
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
_identityService = identityService ?? throw new ArgumentNullException(nameof(identityService));
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
|
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> Handle(CreateOrderCommand message, CancellationToken cancellationToken)
|
public async Task<bool> Handle(CreateOrderCommand message, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
// Add Integration event to clean the basket
|
||||||
|
var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(message.UserId);
|
||||||
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStartedIntegrationEvent);
|
||||||
|
|
||||||
// Add/Update the Buyer AggregateRoot
|
// Add/Update the Buyer AggregateRoot
|
||||||
// DDD patterns comment: Add child entities and value-objects through the Order Aggregate-Root
|
// DDD patterns comment: Add child entities and value-objects through the Order Aggregate-Root
|
||||||
// methods and constructor so validations, invariants and business logic
|
// methods and constructor so validations, invariants and business logic
|
||||||
|
@ -41,7 +41,7 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderCancelled
|
|||||||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
||||||
|
|
||||||
var orderStatusChangedToCancelledIntegrationEvent = new OrderStatusChangedToCancelledIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
|
var orderStatusChangedToCancelledIntegrationEvent = new OrderStatusChangedToCancelledIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
|
||||||
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToCancelledIntegrationEvent);
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedToCancelledIntegrationEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
var orderStatusChangedToAwaitingValidationIntegrationEvent = new OrderStatusChangedToAwaitingValidationIntegrationEvent(
|
var orderStatusChangedToAwaitingValidationIntegrationEvent = new OrderStatusChangedToAwaitingValidationIntegrationEvent(
|
||||||
order.Id, order.OrderStatus.Name, buyer.Name, orderStockList);
|
order.Id, order.OrderStatus.Name, buyer.Name, orderStockList);
|
||||||
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToAwaitingValidationIntegrationEvent);
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedToAwaitingValidationIntegrationEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -51,7 +51,7 @@
|
|||||||
buyer.Name,
|
buyer.Name,
|
||||||
orderStockList);
|
orderStockList);
|
||||||
|
|
||||||
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToPaidIntegrationEvent);
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedToPaidIntegrationEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -41,7 +41,7 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderShipped
|
|||||||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
||||||
|
|
||||||
var orderStatusChangedToShippedIntegrationEvent = new OrderStatusChangedToShippedIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
|
var orderStatusChangedToShippedIntegrationEvent = new OrderStatusChangedToShippedIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
|
||||||
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToShippedIntegrationEvent);
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedToShippedIntegrationEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
|
|||||||
.SaveEntitiesAsync();
|
.SaveEntitiesAsync();
|
||||||
|
|
||||||
var orderStatusChangedTosubmittedIntegrationEvent = new OrderStatusChangedToSubmittedIntegrationEvent(orderStartedEvent.Order.Id, orderStartedEvent.Order.OrderStatus.Name, buyer.Name);
|
var orderStatusChangedTosubmittedIntegrationEvent = new OrderStatusChangedToSubmittedIntegrationEvent(orderStartedEvent.Order.Id, orderStartedEvent.Order.OrderStatus.Name, buyer.Name);
|
||||||
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedTosubmittedIntegrationEvent);
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedTosubmittedIntegrationEvent);
|
||||||
|
|
||||||
_logger.CreateLogger(nameof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler)).LogTrace($"Buyer {buyerUpdated.Id} and related payment method were validated or updated for orderId: {orderStartedEvent.Order.Id}.");
|
_logger.CreateLogger(nameof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler)).LogTrace($"Buyer {buyerUpdated.Id} and related payment method were validated or updated for orderId: {orderStartedEvent.Order.Id}.");
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
|
||||||
|
|
||||||
var orderStatusChangedToStockConfirmedIntegrationEvent = new OrderStatusChangedToStockConfirmedIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
|
var orderStatusChangedToStockConfirmedIntegrationEvent = new OrderStatusChangedToStockConfirmedIntegrationEvent(order.Id, order.OrderStatus.Name, buyer.Name);
|
||||||
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToStockConfirmedIntegrationEvent);
|
await _orderingIntegrationEventService.AddAndSaveEventAsync(orderStatusChangedToStockConfirmedIntegrationEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,15 +11,13 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
|||||||
public class UserCheckoutAcceptedIntegrationEventHandler : IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>
|
public class UserCheckoutAcceptedIntegrationEventHandler : IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
private readonly ILoggerFactory _logger;
|
private readonly ILoggerFactory _logger;
|
||||||
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
|
||||||
|
|
||||||
public UserCheckoutAcceptedIntegrationEventHandler(IMediator mediator,
|
public UserCheckoutAcceptedIntegrationEventHandler(IMediator mediator,
|
||||||
ILoggerFactory logger, IOrderingIntegrationEventService orderingIntegrationEventService)
|
ILoggerFactory logger)
|
||||||
{
|
{
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -34,11 +32,7 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
|||||||
public async Task Handle(UserCheckoutAcceptedIntegrationEvent eventMsg)
|
public async Task Handle(UserCheckoutAcceptedIntegrationEvent eventMsg)
|
||||||
{
|
{
|
||||||
var result = false;
|
var result = false;
|
||||||
|
|
||||||
// Send Integration event to clean basket once basket is converted to Order and before starting with the order creation process
|
|
||||||
var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(eventMsg.UserId);
|
|
||||||
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStartedIntegrationEvent);
|
|
||||||
|
|
||||||
if (eventMsg.RequestId != Guid.Empty)
|
if (eventMsg.RequestId != Guid.Empty)
|
||||||
{
|
{
|
||||||
var createOrderCommand = new CreateOrderCommand(eventMsg.Basket.Items, eventMsg.UserId, eventMsg.UserName, eventMsg.City, eventMsg.Street,
|
var createOrderCommand = new CreateOrderCommand(eventMsg.Basket.Items, eventMsg.UserId, eventMsg.UserName, eventMsg.City, eventMsg.Street,
|
||||||
|
@ -5,6 +5,7 @@ namespace Ordering.API.Application.IntegrationEvents
|
|||||||
{
|
{
|
||||||
public interface IOrderingIntegrationEventService
|
public interface IOrderingIntegrationEventService
|
||||||
{
|
{
|
||||||
Task PublishThroughEventBusAsync(IntegrationEvent evt);
|
Task PublishEventsThroughEventBusAsync();
|
||||||
|
Task AddAndSaveEventAsync(IntegrationEvent evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,23 +34,27 @@ namespace Ordering.API.Application.IntegrationEvents
|
|||||||
_eventLogService = _integrationEventLogServiceFactory(_orderingContext.Database.GetDbConnection());
|
_eventLogService = _integrationEventLogServiceFactory(_orderingContext.Database.GetDbConnection());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PublishThroughEventBusAsync(IntegrationEvent evt)
|
public async Task PublishEventsThroughEventBusAsync()
|
||||||
{
|
{
|
||||||
await SaveEventAsync(evt);
|
var pendindLogEvents = await _eventLogService.RetrieveEventLogsPendingToPublishAsync();
|
||||||
_eventBus.Publish(evt);
|
foreach (var logEvt in pendindLogEvents)
|
||||||
await _eventLogService.MarkEventAsPublishedAsync(evt);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _eventLogService.MarkEventAsInProgressAsync(logEvt.EventId);
|
||||||
|
_eventBus.Publish(logEvt.IntegrationEvent);
|
||||||
|
await _eventLogService.MarkEventAsPublishedAsync(logEvt.EventId);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
await _eventLogService.MarkEventAsFailedAsync(logEvt.EventId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveEventAsync(IntegrationEvent evt)
|
public async Task AddAndSaveEventAsync(IntegrationEvent evt)
|
||||||
{
|
{
|
||||||
var strategy = _orderingContext.Database.CreateExecutionStrategy();
|
await _eventLogService.SaveEventAsync(evt, _orderingContext.GetCurrentTransaction.GetDbTransaction());
|
||||||
await strategy.ExecuteAsync(async () =>
|
|
||||||
{
|
|
||||||
await _orderingContext.BeginTransactionAsync();
|
|
||||||
await _eventLogService.SaveEventAsync(evt, _orderingContext.GetCurrentTransaction.GetDbTransaction());
|
|
||||||
await _orderingContext.CommitTransactionAsync();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,13 @@
|
|||||||
eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>();
|
eventBus.Subscribe<OrderStockRejectedIntegrationEvent, IIntegrationEventHandler<OrderStockRejectedIntegrationEvent>>();
|
||||||
eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>();
|
eventBus.Subscribe<OrderPaymentFailedIntegrationEvent, IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>>();
|
||||||
eventBus.Subscribe<OrderPaymentSuccededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>>();
|
eventBus.Subscribe<OrderPaymentSuccededIntegrationEvent, IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStartedIntegrationEvent, IIntegrationEventHandler<OrderStartedIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToAwaitingValidationIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToAwaitingValidationIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToCancelledIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToCancelledIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToPaidIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToShippedIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToSubmittedIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToSubmittedIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToStockConfirmedIntegrationEvent, IIntegrationEventHandler<OrderStatusChangedToStockConfirmedIntegrationEvent>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -251,7 +258,11 @@
|
|||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
services.AddTransient<IIdentityService, IdentityService>();
|
services.AddTransient<IIdentityService, IdentityService>();
|
||||||
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
||||||
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
sp =>
|
||||||
|
{
|
||||||
|
var busMgr = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
return (DbConnection c) => new IntegrationEventLogService(busMgr, c);
|
||||||
|
});
|
||||||
|
|
||||||
services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user