Hej, chciałbym prosić Was o opinie. Proces jest taki: user składa zamówienie, złożone zamówienie musi lecieć do zewn systemu przy pomocy restowego API.
Mechanizm działa, natomiast pytanie czy to jest OK? czy coś byście zmienili, usprawnili, poprawili?
kontroler
public class OrderController(IOrderService orderService, IOrderProcessingService orderProcessingService) : ControllerBase
{
[HttpPost("add")]
public async Task<IActionResult> RegisterOrder([FromBody] OrderRequest orderRequest)
{
if(orderRequest == null)
{
return BadRequest();
}
var order = await orderService.CreateOrder(orderRequest);
if(order is null)
{
return StatusCode(500, "Order creation failed");
}
//Prepare object for sending
var orderToErp = orderService.PrepareOrder(order);
if (orderToErp == null)
{
return StatusCode(500, "Failed to prepare order for ERP.");
}
// Enqueue the order for background processing and send to ERP
orderProcessingService.EnqueueOrder(orderToErp);
// ... reszta kodu
}
public class OrderQueue
{
private readonly ConcurrentQueue<ERP_OrderRootObject> _orders = new ConcurrentQueue<ERP_OrderRootObject>();
public void Enqueue(ERP_OrderRootObject orderToErp) { _orders.Enqueue(orderToErp); }
public bool TryDequeue(out ERP_OrderRootObject orderToErp)
{
return _orders.TryDequeue(out orderToErp);
}
}
public interface IOrderProcessingService
{
Task SendOrderToErpAsync(ERP_OrderRootObject orderToErp);
void EnqueueOrder(ERP_OrderRootObject orderToErp);
}
public class OrderProcessingService(
OrderQueue orderQueue,
ILogger<OrderProcessingService> logger,
IServiceScopeFactory serviceScopeFactory
) : BackgroundService, IOrderProcessingService
{
public void EnqueueOrder(ERP_OrderRootObject orderToErp)
{
orderQueue.Enqueue(orderToErp);
}
public async Task SendOrderToErpAsync(ERP_OrderRootObject orderToErp)
{
// Resolve the scoped service within the method
using (var scope = serviceScopeFactory.CreateScope())
{
logger.LogInformation("....:::: BEGIN : sending something to ERP in the background ::::....");
var microsoftService = scope.ServiceProvider.GetRequiredService<IMicrosoftService>();
var httpClientFactory = scope.ServiceProvider.GetRequiredService<IHttpClientFactory>();
// generalnie komunikacja z zewn. API
logger.LogInformation("....:::: END : sending something to D365 in the background ::::....");
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
if (orderQueue.TryDequeue(out var orderToErp))
{
try
{
await SendOrderToErpAsync(orderToErp);
logger.LogInformation("Order {OrderId} sent to ERP successfully.", orderToErp.OrderHeaderClass.MessageId);
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to send order {OrderId} to ERP.", orderToErp.OrderHeaderClass.MessageId);
// Handle failure (e.g., retry, log for manual processing, etc.)
}
}
await Task.Delay(1000, stoppingToken);
}
}
}
oraz rejestracja
// Register the order queue as a singleton
services.AddSingleton<OrderQueue>();
// Register the factory and background service
services.AddSingleton<IOrderProcessingService, OrderProcessingService>();
services.AddHostedService<OrderProcessingService>();