From fdeaffce717ac730d7560d63150beaf071f9690d Mon Sep 17 00:00:00 2001
From: Philipp Theyssen
Date: Thu, 23 Mar 2023 19:49:25 +0100
Subject: [PATCH] Add event bus events for catalog service.
---
.../Controllers/CatalogController.cs | 41 +++++++++++++++++++
.../Events/ProductCreatedIntegrationEvent.cs | 39 ++++++++++++++++++
.../Events/ProductDeletedIntegrationEvent.cs | 11 +++++
.../ProductStockChangedIntegrationEvent.cs | 20 +++++++++
4 files changed, 111 insertions(+)
create mode 100644 src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductCreatedIntegrationEvent.cs
create mode 100644 src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductDeletedIntegrationEvent.cs
create mode 100644 src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductStockChangedIntegrationEvent.cs
diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs
index 4dd1143f6..2ab4ccb7f 100644
--- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs
+++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs
@@ -216,7 +216,9 @@ public class CatalogController : ControllerBase
}
var oldPrice = catalogItem.Price;
+ var oldStock = catalogItem.AvailableStock;
var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price;
+ var raiseProductStockChangedEvent = oldStock != productToUpdate.AvailableStock;
// Update current product
catalogItem = productToUpdate;
@@ -233,6 +235,18 @@ public class CatalogController : ControllerBase
// Publish through the Event Bus and mark the saved event as published
await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent);
}
+ else if (raiseProductStockChangedEvent)
+ {
+ // Create Integration Event to be published through the Event Bus
+ var stockChangedEvent = new ProductStockChangedIntegrationEvent(catalogItem.Id, productToUpdate.AvailableStock, oldStock);
+
+ // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
+ await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(stockChangedEvent);
+
+ // Publish through the Event Bus and mark the saved event as published
+ await _catalogIntegrationEventService.PublishThroughEventBusAsync(stockChangedEvent);
+
+ }
else // Just save the updated product because the Product's Price hasn't changed.
{
await _catalogContext.SaveChangesAsync();
@@ -261,6 +275,26 @@ public class CatalogController : ControllerBase
await _catalogContext.SaveChangesAsync();
+ // publish CatalogItemCreatedIntegrationEvent
+ var productCreatedEvent = new ProductCreatedIntegrationEvent()
+ {
+ AvailableStock = item.AvailableStock,
+ CatalogBrand = item.CatalogBrand,
+ CatalogBrandId = item.CatalogBrandId,
+ CatalogType = item.CatalogType,
+ CatalogTypeId = item.CatalogTypeId,
+ Description = item.Description,
+ Id = item.Id,
+ MaxStockThreshold = item.MaxStockThreshold,
+ Name = item.Name,
+ OnReorder = item.OnReorder
+ };
+ // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
+ await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(productCreatedEvent);
+
+ // Publish through the Event Bus and mark the saved event as published
+ await _catalogIntegrationEventService.PublishThroughEventBusAsync(productCreatedEvent);
+
return CreatedAtAction(nameof(ItemByIdAsync), new { id = item.Id }, null);
}
@@ -282,6 +316,13 @@ public class CatalogController : ControllerBase
await _catalogContext.SaveChangesAsync();
+ var productDeletedEvent = new ProductDeletedIntegrationEvent(product.Id);
+ // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
+ await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(productDeletedEvent);
+
+ // Publish through the Event Bus and mark the saved event as published
+ await _catalogIntegrationEventService.PublishThroughEventBusAsync(productDeletedEvent);
+
return NoContent();
}
diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductCreatedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductCreatedIntegrationEvent.cs
new file mode 100644
index 000000000..a670da604
--- /dev/null
+++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductCreatedIntegrationEvent.cs
@@ -0,0 +1,39 @@
+namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
+
+public record ProductCreatedIntegrationEvent : IntegrationEvent
+{
+ public int Id { get; set; }
+
+ public string Name { get; set; }
+
+ public string Description { get; set; }
+
+ public decimal Price { get; set; }
+
+ public string PictureFileName { get; set; }
+
+ public string PictureUri { get; set; }
+
+ public int CatalogTypeId { get; set; }
+
+ public CatalogType CatalogType { get; set; }
+
+ public int CatalogBrandId { get; set; }
+
+ public CatalogBrand CatalogBrand { get; set; }
+
+ // Quantity in stock
+ public int AvailableStock { get; set; }
+
+ // Available stock at which we should reorder
+ public int RestockThreshold { get; set; }
+
+
+ // Maximum number of units that can be in-stock at any time (due to physicial/logistical constraints in warehouses)
+ public int MaxStockThreshold { get; set; }
+
+ ///
+ /// True if item is on reorder
+ ///
+ public bool OnReorder { get; set; }
+}
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductDeletedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductDeletedIntegrationEvent.cs
new file mode 100644
index 000000000..09bc2d383
--- /dev/null
+++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductDeletedIntegrationEvent.cs
@@ -0,0 +1,11 @@
+namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
+
+public record ProductDeletedIntegrationEvent : IntegrationEvent
+{
+ public int ProductId { get; private init; }
+
+ public ProductDeletedIntegrationEvent(int productId)
+ {
+ ProductId = productId;
+ }
+}
\ No newline at end of file
diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductStockChangedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductStockChangedIntegrationEvent.cs
new file mode 100644
index 000000000..c64f24761
--- /dev/null
+++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductStockChangedIntegrationEvent.cs
@@ -0,0 +1,20 @@
+namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
+
+// Integration Events notes:
+// An Event is “something that has happened in the past”, therefore its name has to be past tense
+// An Integration Event is an event that can cause side effects to other microservices, Bounded-Contexts or external systems.
+public record ProductStockChangedIntegrationEvent : IntegrationEvent
+{
+ public int ProductId { get; private init; }
+
+ public decimal NewStock { get; private init; }
+
+ public decimal OldStock { get; private init; }
+
+ public ProductStockChangedIntegrationEvent(int productId, decimal newStock, decimal oldStock)
+ {
+ ProductId = productId;
+ NewStock = newStock;
+ OldStock = oldStock;
+ }
+}
\ No newline at end of file