From d47ff517ad46d09ec794c2efbf27328f36a1b42d Mon Sep 17 00:00:00 2001 From: hello Date: Tue, 8 Oct 2024 22:08:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=88=86=E5=B8=83=E5=BC=8F?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=AE=9E=E7=8E=B0=E8=AE=A2=E5=8D=95=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=BA=93=E5=AD=98=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...PaymentSucceededDistributedEventHandler.cs | 42 ++++++++++++++++ .../Events/OrderPaidDistributedEvent.cs | 9 ++++ .../OrderPaymentFailedDistributedEvent.cs | 14 ++++++ .../OrderPaymentSucceededDistributedEvent.cs | 9 ++++ .../Extensions/Extensions.cs | 1 + .../Workers/PaymentWorker.cs | 50 +++++++++++++++++++ .../OrderPaidDistributedEventHandler.cs | 25 ++++++++++ .../Events/OrderPaidDistributedEvent.cs | 9 ++++ 8 files changed, 159 insertions(+) create mode 100644 src/HelloShop.OrderingService/DistributedEvents/EventHandling/OrderPaymentSucceededDistributedEventHandler.cs create mode 100644 src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaidDistributedEvent.cs create mode 100644 src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaymentFailedDistributedEvent.cs create mode 100644 src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaymentSucceededDistributedEvent.cs create mode 100644 src/HelloShop.OrderingService/Workers/PaymentWorker.cs create mode 100644 src/HelloShop.ProductService/DistributedEvents/EventHandling/OrderPaidDistributedEventHandler.cs create mode 100644 src/HelloShop.ProductService/DistributedEvents/Events/OrderPaidDistributedEvent.cs diff --git a/src/HelloShop.OrderingService/DistributedEvents/EventHandling/OrderPaymentSucceededDistributedEventHandler.cs b/src/HelloShop.OrderingService/DistributedEvents/EventHandling/OrderPaymentSucceededDistributedEventHandler.cs new file mode 100644 index 0000000..34c6cc0 --- /dev/null +++ b/src/HelloShop.OrderingService/DistributedEvents/EventHandling/OrderPaymentSucceededDistributedEventHandler.cs @@ -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 + { + public async Task HandleAsync(OrderPaymentSucceededDistributedEvent @event) + { + var strategy = dbContext.Database.CreateExecutionStrategy(); + + await strategy.ExecuteAsync(async () => + { + await using var transaction = await dbContext.Database.BeginTransactionAsync(); + + DbSet orders = dbContext.Set(); + + 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); + }); + } + } +} diff --git a/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaidDistributedEvent.cs b/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaidDistributedEvent.cs new file mode 100644 index 0000000..1f928a7 --- /dev/null +++ b/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaidDistributedEvent.cs @@ -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 OrderStockItems) : DistributedEvent; +} diff --git a/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaymentFailedDistributedEvent.cs b/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaymentFailedDistributedEvent.cs new file mode 100644 index 0000000..248f5b3 --- /dev/null +++ b/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaymentFailedDistributedEvent.cs @@ -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; + } +} diff --git a/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaymentSucceededDistributedEvent.cs b/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaymentSucceededDistributedEvent.cs new file mode 100644 index 0000000..07e0cb4 --- /dev/null +++ b/src/HelloShop.OrderingService/DistributedEvents/Events/OrderPaymentSucceededDistributedEvent.cs @@ -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; +} diff --git a/src/HelloShop.OrderingService/Extensions/Extensions.cs b/src/HelloShop.OrderingService/Extensions/Extensions.cs index d4cfde7..2acae5e 100644 --- a/src/HelloShop.OrderingService/Extensions/Extensions.cs +++ b/src/HelloShop.OrderingService/Extensions/Extensions.cs @@ -47,6 +47,7 @@ namespace HelloShop.OrderingService.Extensions }); builder.Services.AddHostedService(); + builder.Services.AddHostedService(); } public static WebApplication MapApplicationEndpoints(this WebApplication app) diff --git a/src/HelloShop.OrderingService/Workers/PaymentWorker.cs b/src/HelloShop.OrderingService/Workers/PaymentWorker.cs new file mode 100644 index 0000000..05cda9f --- /dev/null +++ b/src/HelloShop.OrderingService/Workers/PaymentWorker.cs @@ -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 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(); + var distributedEventBus = scope.ServiceProvider.GetRequiredService(); + + bool paymentSucceeded = Random.Shared.NextDouble() > 0.3; + + try + { + var orders = await dbContext.Set().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); + } + } + } +} diff --git a/src/HelloShop.ProductService/DistributedEvents/EventHandling/OrderPaidDistributedEventHandler.cs b/src/HelloShop.ProductService/DistributedEvents/EventHandling/OrderPaidDistributedEventHandler.cs new file mode 100644 index 0000000..a21c94d --- /dev/null +++ b/src/HelloShop.ProductService/DistributedEvents/EventHandling/OrderPaidDistributedEventHandler.cs @@ -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 + { + public async Task HandleAsync(OrderPaidDistributedEvent @event) + { + foreach (var orderStockItem in @event.OrderStockItems) + { + var product = await dbContext.Set().FindAsync(orderStockItem.ProductId) ?? throw new Exception($"Product with id {orderStockItem.ProductId} not found"); + + product.AvailableStock -= orderStockItem.Units; + } + + await dbContext.SaveChangesAsync(); + } + } +} diff --git a/src/HelloShop.ProductService/DistributedEvents/Events/OrderPaidDistributedEvent.cs b/src/HelloShop.ProductService/DistributedEvents/Events/OrderPaidDistributedEvent.cs new file mode 100644 index 0000000..240864b --- /dev/null +++ b/src/HelloShop.ProductService/DistributedEvents/Events/OrderPaidDistributedEvent.cs @@ -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 OrderStockItems) : DistributedEvent; +}