使用分布式事件实现订单支付库存通知
This commit is contained in:
parent
c16d6ece15
commit
d47ff517ad
@ -0,0 +1,42 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.OrderingService.DistributedEvents.Events;
|
||||
using HelloShop.OrderingService.Entities.Orders;
|
||||
using HelloShop.OrderingService.Infrastructure;
|
||||
using HelloShop.ServiceDefaults.DistributedEvents.Abstractions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HelloShop.OrderingService.DistributedEvents.EventHandling
|
||||
{
|
||||
public class OrderPaymentSucceededDistributedEventHandler(OrderingServiceDbContext dbContext, IDistributedEventBus distributedEventBus) : IDistributedEventHandler<OrderPaymentSucceededDistributedEvent>
|
||||
{
|
||||
public async Task HandleAsync(OrderPaymentSucceededDistributedEvent @event)
|
||||
{
|
||||
var strategy = dbContext.Database.CreateExecutionStrategy();
|
||||
|
||||
await strategy.ExecuteAsync(async () =>
|
||||
{
|
||||
await using var transaction = await dbContext.Database.BeginTransactionAsync();
|
||||
|
||||
DbSet<Order> orders = dbContext.Set<Order>();
|
||||
|
||||
Order order = await orders.FindAsync(@event.OrderId) ?? throw new Exception($"Order with id {@event.OrderId} not found");
|
||||
|
||||
await orders.Entry(order).Collection(i => i.OrderItems).LoadAsync();
|
||||
|
||||
order.OrderStatus = OrderStatus.Paid;
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
await transaction.CommitAsync();
|
||||
|
||||
var orderStockList = order.OrderItems.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.Units));
|
||||
|
||||
var integrationEvent = new OrderPaidDistributedEvent(order.Id, orderStockList);
|
||||
|
||||
await distributedEventBus.PublishAsync(integrationEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ServiceDefaults.DistributedEvents.Abstractions;
|
||||
|
||||
namespace HelloShop.OrderingService.DistributedEvents.Events
|
||||
{
|
||||
public record OrderPaidDistributedEvent(int OrderId, IEnumerable<OrderStockItem> OrderStockItems) : DistributedEvent;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ServiceDefaults.DistributedEvents.Abstractions;
|
||||
|
||||
namespace HelloShop.OrderingService.DistributedEvents.Events
|
||||
{
|
||||
public record OrderPaymentFailedDistributedEvent : DistributedEvent
|
||||
{
|
||||
public int OrderId { get; }
|
||||
|
||||
public OrderPaymentFailedDistributedEvent(int orderId) => OrderId = orderId;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ServiceDefaults.DistributedEvents.Abstractions;
|
||||
|
||||
namespace HelloShop.OrderingService.DistributedEvents.Events
|
||||
{
|
||||
public record OrderPaymentSucceededDistributedEvent(int OrderId) : DistributedEvent;
|
||||
}
|
@ -47,6 +47,7 @@ namespace HelloShop.OrderingService.Extensions
|
||||
});
|
||||
|
||||
builder.Services.AddHostedService<GracePeriodWorker>();
|
||||
builder.Services.AddHostedService<PaymentWorker>();
|
||||
}
|
||||
|
||||
public static WebApplication MapApplicationEndpoints(this WebApplication app)
|
||||
|
50
src/HelloShop.OrderingService/Workers/PaymentWorker.cs
Normal file
50
src/HelloShop.OrderingService/Workers/PaymentWorker.cs
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.OrderingService.DistributedEvents.Events;
|
||||
using HelloShop.OrderingService.Entities.Orders;
|
||||
using HelloShop.OrderingService.Infrastructure;
|
||||
using HelloShop.ServiceDefaults.DistributedEvents.Abstractions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HelloShop.OrderingService.Workers
|
||||
{
|
||||
public class PaymentWorker(IServiceScopeFactory serviceScopeFactory, ILogger<PaymentWorker> logger) : BackgroundService
|
||||
{
|
||||
protected async override Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
if (logger.IsEnabled(LogLevel.Information))
|
||||
{
|
||||
logger.LogInformation("{Worker} background task is doing background work.", GetType().Name);
|
||||
}
|
||||
|
||||
using var scope = serviceScopeFactory.CreateAsyncScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<OrderingServiceDbContext>();
|
||||
var distributedEventBus = scope.ServiceProvider.GetRequiredService<IDistributedEventBus>();
|
||||
|
||||
bool paymentSucceeded = Random.Shared.NextDouble() > 0.3;
|
||||
|
||||
try
|
||||
{
|
||||
var orders = await dbContext.Set<Order>().Include(o => o.OrderItems).Where(o => o.OrderStatus == OrderStatus.StockConfirmed).ToListAsync(stoppingToken);
|
||||
|
||||
foreach (var order in orders)
|
||||
{
|
||||
DistributedEvent @event = paymentSucceeded ? new OrderPaymentSucceededDistributedEvent(order.Id) : new OrderPaymentFailedDistributedEvent(order.Id);
|
||||
|
||||
await distributedEventBus.PublishAsync(@event, stoppingToken);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error occurred executing {Worker} background task.", GetType().Name);
|
||||
}
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ProductService.DistributedEvents.Events;
|
||||
using HelloShop.ProductService.Entities.Products;
|
||||
using HelloShop.ProductService.Infrastructure;
|
||||
using HelloShop.ServiceDefaults.DistributedEvents.Abstractions;
|
||||
|
||||
namespace HelloShop.ProductService.DistributedEvents.EventHandling
|
||||
{
|
||||
public class OrderPaidDistributedEventHandler(ProductServiceDbContext dbContext) : IDistributedEventHandler<OrderPaidDistributedEvent>
|
||||
{
|
||||
public async Task HandleAsync(OrderPaidDistributedEvent @event)
|
||||
{
|
||||
foreach (var orderStockItem in @event.OrderStockItems)
|
||||
{
|
||||
var product = await dbContext.Set<Product>().FindAsync(orderStockItem.ProductId) ?? throw new Exception($"Product with id {orderStockItem.ProductId} not found");
|
||||
|
||||
product.AvailableStock -= orderStockItem.Units;
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using HelloShop.ServiceDefaults.DistributedEvents.Abstractions;
|
||||
|
||||
namespace HelloShop.ProductService.DistributedEvents.Events
|
||||
{
|
||||
public record OrderPaidDistributedEvent(int OrderId, IEnumerable<OrderStockItem> OrderStockItems) : DistributedEvent;
|
||||
}
|
Loading…
Reference in New Issue
Block a user