diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/ProductInventories/IProductInventoryProvider.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/ProductInventories/IProductInventoryProvider.cs index eaf89186..981abbed 100644 --- a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/ProductInventories/IProductInventoryProvider.cs +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/ProductInventories/IProductInventoryProvider.cs @@ -12,8 +12,10 @@ namespace EasyAbp.EShop.Products.ProductInventories Task> GetSkuIdInventoryDataMappingAsync(IList models); - Task TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, bool decreaseSold); + Task TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, bool decreaseSold, + bool isFlashSale = false); - Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold); + Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold, + bool isFlashSale = false); } } \ No newline at end of file diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs index 9f420ea2..82b9c1a6 100644 --- a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs @@ -76,7 +76,7 @@ namespace EasyAbp.EShop.Products.Products [UnitOfWork(true)] public virtual async Task TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, - bool decreaseSold) + bool decreaseSold, bool isFlashSale = false) { await using var handle = await _distributedLock.TryAcquireAsync(await GetLockKeyAsync(model), TimeSpan.FromSeconds(30)); @@ -94,7 +94,7 @@ namespace EasyAbp.EShop.Products.Products [UnitOfWork(true)] public virtual async Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, - bool increaseSold) + bool increaseSold, bool isFlashSale = false) { await using var handle = await _distributedLock.TryAcquireAsync(await GetLockKeyAsync(model), TimeSpan.FromSeconds(30)); diff --git a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductManager.cs b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductManager.cs index a6f7e35c..ade8db3d 100644 --- a/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductManager.cs +++ b/modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductManager.cs @@ -259,8 +259,10 @@ namespace EasyAbp.EShop.Products.Products { var model = new InventoryQueryModel(product.TenantId, product.StoreId, product.Id, productSku.Id); + var isFlashSale = product.InventoryStrategy is InventoryStrategy.FlashSales; + return await (await _productInventoryProviderResolver.GetAsync(product)) - .TryIncreaseInventoryAsync(model, quantity, reduceSold); + .TryIncreaseInventoryAsync(model, quantity, reduceSold, isFlashSale); } public virtual async Task TryReduceInventoryAsync(Product product, ProductSku productSku, int quantity, @@ -268,8 +270,10 @@ namespace EasyAbp.EShop.Products.Products { var model = new InventoryQueryModel(product.TenantId, product.StoreId, product.Id, productSku.Id); + var isFlashSale = product.InventoryStrategy is InventoryStrategy.FlashSales; + return await (await _productInventoryProviderResolver.GetAsync(product)) - .TryReduceInventoryAsync(model, quantity, increaseSold); + .TryReduceInventoryAsync(model, quantity, increaseSold, isFlashSale); } public virtual async Task GetRealPriceAsync(Product product, ProductSku productSku) diff --git a/modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.TestBase/FakeProductInventoryProvider.cs b/modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.TestBase/FakeProductInventoryProvider.cs index e49d2ff2..b5c5ddbb 100644 --- a/modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.TestBase/FakeProductInventoryProvider.cs +++ b/modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.TestBase/FakeProductInventoryProvider.cs @@ -34,10 +34,11 @@ public class FakeProductInventoryProvider : IProductInventoryProvider, ITransien return Task.FromResult(result); } - public Task TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, bool decreaseSold) + public Task TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, bool decreaseSold, + bool isFlashSale = false) { Model.Inventory++; - + if (decreaseSold) { Model.Sold--; @@ -46,10 +47,11 @@ public class FakeProductInventoryProvider : IProductInventoryProvider, ITransien return Task.FromResult(true); } - public Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold) + public Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold, + bool isFlashSale = false) { Model.Inventory--; - + if (increaseSold) { Model.Sold++; diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/FlashSaleInventoryManager.cs b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/FlashSaleInventoryManager.cs index 6e6bd678..aaeb31ce 100644 --- a/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/FlashSaleInventoryManager.cs +++ b/plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/FlashSaleInventoryManager.cs @@ -17,17 +17,17 @@ public class FlashSaleInventoryManager : IFlashSaleInventoryManager, ITransientD FlashSaleInventoryReducerAppService = flashSaleInventoryReducerAppService; } - public virtual async Task TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, - Guid productSkuId, int quantity, bool increaseSold) + public virtual async Task TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, + Guid productId, Guid productSkuId, int quantity, bool increaseSold) { - return await FlashSaleInventoryReducerAppService.TryReduceAsync( - new ReduceInventoryInput(tenantId, providerName, storeId, productId, productSkuId, quantity, increaseSold)); + return await FlashSaleInventoryReducerAppService.TryReduceAsync(new ReduceInventoryInput( + tenantId, providerName, storeId, productId, productSkuId, quantity, increaseSold)); } - public virtual async Task TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, - Guid productSkuId, int quantity, bool decreaseSold) + public virtual async Task TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, + Guid productId, Guid productSkuId, int quantity, bool decreaseSold) { - return await FlashSaleInventoryReducerAppService.TryIncreaseAsync - (new IncreaseInventoryInput(tenantId, providerName, storeId, productId, productSkuId, quantity, decreaseSold)); + return await FlashSaleInventoryReducerAppService.TryIncreaseAsync(new IncreaseInventoryInput( + tenantId, providerName, storeId, productId, productSkuId, quantity, decreaseSold)); } -} +} \ No newline at end of file diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Abstractions/EasyAbp/Eshop/Products/Products/IFlashSaleInventoryManager.cs b/plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Abstractions/EasyAbp/Eshop/Products/Products/IFlashSaleInventoryManager.cs index 2fa36304..93558adc 100644 --- a/plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Abstractions/EasyAbp/Eshop/Products/Products/IFlashSaleInventoryManager.cs +++ b/plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Abstractions/EasyAbp/Eshop/Products/Products/IFlashSaleInventoryManager.cs @@ -5,7 +5,9 @@ namespace EasyAbp.Eshop.Products.Products; public interface IFlashSaleInventoryManager { - Task TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool increaseSold); + Task TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, + Guid productSkuId, int quantity, bool increaseSold); - Task TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool decreaseSold); -} + Task TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, + Guid productSkuId, int quantity, bool decreaseSold); +} \ No newline at end of file diff --git a/plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/LocalFlashSaleInventoryManager.cs b/plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/LocalFlashSaleInventoryManager.cs index 093b7ed3..6e38ba04 100644 --- a/plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/LocalFlashSaleInventoryManager.cs +++ b/plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/LocalFlashSaleInventoryManager.cs @@ -20,7 +20,7 @@ public class LocalFlashSaleInventoryManager : ILocalFlashSaleInventoryManager, I { var model = new InventoryQueryModel(tenantId, storeId, productId, productSkuId); return await (await ProductInventoryProviderResolver.GetAsync(providerName)) - .TryReduceInventoryAsync(model, quantity, increaseSold); + .TryReduceInventoryAsync(model, quantity, increaseSold, true); } public virtual async Task TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, @@ -28,6 +28,6 @@ public class LocalFlashSaleInventoryManager : ILocalFlashSaleInventoryManager, I { var model = new InventoryQueryModel(tenantId, storeId, productId, productSkuId); return await (await ProductInventoryProviderResolver.GetAsync(providerName)) - .TryIncreaseInventoryAsync(model, quantity, decreaseSold); + .TryIncreaseInventoryAsync(model, quantity, decreaseSold, true); } } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeFlashSaleInventoryManager.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeFlashSaleInventoryManager.cs index ff159deb..866e3b8c 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeFlashSaleInventoryManager.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeFlashSaleInventoryManager.cs @@ -13,15 +13,15 @@ public class FakeFlashSaleInventoryManager : IFlashSaleInventoryManager ShouldReduceSuccess = true; } - public Task TryReduceInventoryAsync( - Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool increaseSold) + public Task TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, + Guid productSkuId, int quantity, bool increaseSold) { return Task.FromResult(ShouldReduceSuccess); } - public Task TryRollBackInventoryAsync( - Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool decreaseSold) + public Task TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, + Guid productSkuId, int quantity, bool decreaseSold) { return Task.FromResult(true); } -} +} \ No newline at end of file diff --git a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors.Abstractions/EasyAbp/EShop/Plugins/Inventories/DaprActors/IInventoryActor.cs b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors.Abstractions/EasyAbp/EShop/Plugins/Inventories/DaprActors/IInventoryActor.cs index 714904b5..8a585518 100644 --- a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors.Abstractions/EasyAbp/EShop/Plugins/Inventories/DaprActors/IInventoryActor.cs +++ b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors.Abstractions/EasyAbp/EShop/Plugins/Inventories/DaprActors/IInventoryActor.cs @@ -7,7 +7,7 @@ public interface IInventoryActor : IActor { Task GetInventoryStateAsync(); - Task IncreaseInventoryAsync(int quantity, bool decreaseSold); + Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale); - Task ReduceInventoryAsync(int quantity, bool increaseSold); + Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale); } \ No newline at end of file diff --git a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp.EShop.Plugins.Inventories.DaprActors.csproj b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp.EShop.Plugins.Inventories.DaprActors.csproj index 4b5cd92d..386df1c6 100644 --- a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp.EShop.Plugins.Inventories.DaprActors.csproj +++ b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp.EShop.Plugins.Inventories.DaprActors.csproj @@ -12,6 +12,7 @@ + diff --git a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/EShopPluginsInventoriesDaprActorsModule.cs b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/EShopPluginsInventoriesDaprActorsModule.cs index 0b59cb9b..65b224a5 100644 --- a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/EShopPluginsInventoriesDaprActorsModule.cs +++ b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/EShopPluginsInventoriesDaprActorsModule.cs @@ -1,8 +1,10 @@ using Volo.Abp.Modularity; +using Volo.Abp.Timing; namespace EasyAbp.EShop.Plugins.Inventories.DaprActors; [DependsOn( + typeof(AbpTimingModule), typeof(EShopPluginsInventoriesDaprActorsAbstractionsModule) )] public class EShopPluginsInventoriesDaprActorsModule : AbpModule diff --git a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/InventoryActor.cs b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/InventoryActor.cs index 28457019..3eedce1f 100644 --- a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/InventoryActor.cs +++ b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/InventoryActor.cs @@ -1,6 +1,8 @@ +using System; using System.Threading.Tasks; using Dapr; using Dapr.Actors.Runtime; +using Volo.Abp.Timing; namespace EasyAbp.EShop.Plugins.Inventories.DaprActors; @@ -8,8 +10,13 @@ public class InventoryActor : Actor, IInventoryActor { public static string InventoryStateName { get; set; } = "i"; - public InventoryActor(ActorHost host) : base(host) + protected DateTime? TimeToPersistInventory { get; set; } + + protected IClock Clock { get; } + + public InventoryActor(ActorHost host, IClock clock) : base(host) { + Clock = clock; } protected override async Task OnActivateAsync() @@ -19,25 +26,62 @@ public class InventoryActor : Actor, IInventoryActor public virtual async Task GetInventoryStateAsync() { - return await StateManager.GetStateAsync(InventoryStateName); + var state = await InternalGetInventoryStateAsync(); + + await TrySetInventoryStateAsync(state); + + return state; } - public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold) + public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale) { - var state = await GetInventoryStateAsync(); + var state = await InternalGetInventoryStateAsync(); InternalIncreaseInventory(state, quantity, decreaseSold); - await SetInventoryStateAsync(state); + if (!isFlashSale || state.Inventory == 0) + { + await SetInventoryStateAsync(state); + } + else + { + TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30); + + await TrySetInventoryStateAsync(state); + } } - public async Task ReduceInventoryAsync(int quantity, bool increaseSold) + public virtual async Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale) { - var state = await GetInventoryStateAsync(); + var state = await InternalGetInventoryStateAsync(); InternalReduceInventory(state, quantity, increaseSold); - await SetInventoryStateAsync(state); + if (!isFlashSale || state.Inventory == 0) + { + await SetInventoryStateAsync(state); + } + else + { + TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30); + + await TrySetInventoryStateAsync(state); + } + } + + public virtual Task InternalGetInventoryStateAsync() => + StateManager.GetStateAsync(InventoryStateName); + + public async Task TrySetInventoryStateAsync(InventoryStateModel stateModel) + { + if (!TimeToPersistInventory.HasValue || TimeToPersistInventory.Value < Clock.Now) + { + return false; + } + + await SetInventoryStateAsync(stateModel); + + return true; } protected virtual async Task SetInventoryStateAsync(InventoryStateModel state) diff --git a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Products.DaprActorsInventory.Domain/EasyAbp/EShop/Products/DaprActorsInventory/DaprActorsProductInventoryProvider.cs b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Products.DaprActorsInventory.Domain/EasyAbp/EShop/Products/DaprActorsInventory/DaprActorsProductInventoryProvider.cs index 73f072fb..4b496af2 100644 --- a/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Products.DaprActorsInventory.Domain/EasyAbp/EShop/Products/DaprActorsInventory/DaprActorsProductInventoryProvider.cs +++ b/plugins/Inventories/DaprActors/src/EasyAbp.EShop.Products.DaprActorsInventory.Domain/EasyAbp/EShop/Products/DaprActorsInventory/DaprActorsProductInventoryProvider.cs @@ -57,13 +57,13 @@ public class DaprActorsProductInventoryProvider : IProductInventoryProvider, ITr } public virtual async Task TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, - bool decreaseSold) + bool decreaseSold, bool isFlashSale = false) { var actor = await GetActorAsync(model); try { - await actor.IncreaseInventoryAsync(quantity, decreaseSold); + await actor.IncreaseInventoryAsync(quantity, decreaseSold, isFlashSale); } catch (Exception e) { @@ -75,7 +75,8 @@ public class DaprActorsProductInventoryProvider : IProductInventoryProvider, ITr return true; } - public virtual async Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold) + public virtual async Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold, + bool isFlashSale = false) { var actor = await GetActorAsync(model); @@ -88,7 +89,7 @@ public class DaprActorsProductInventoryProvider : IProductInventoryProvider, ITr try { - await actor.ReduceInventoryAsync(quantity, increaseSold); + await actor.ReduceInventoryAsync(quantity, increaseSold, isFlashSale); } catch (Exception e) { diff --git a/plugins/Inventories/DaprActors/test/EasyAbp.EShop.Products.DaprActorsInventory.Domain.Tests/FakeInventoryActor.cs b/plugins/Inventories/DaprActors/test/EasyAbp.EShop.Products.DaprActorsInventory.Domain.Tests/FakeInventoryActor.cs index 58ae0129..fba881f9 100644 --- a/plugins/Inventories/DaprActors/test/EasyAbp.EShop.Products.DaprActorsInventory.Domain.Tests/FakeInventoryActor.cs +++ b/plugins/Inventories/DaprActors/test/EasyAbp.EShop.Products.DaprActorsInventory.Domain.Tests/FakeInventoryActor.cs @@ -17,7 +17,7 @@ public class FakeInventoryActor : IInventoryActor, ITransientDependency return Task.FromResult(StateModel); } - public Task IncreaseInventoryAsync(int quantity, bool decreaseSold) + public Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale) { StateModel.Inventory += quantity; @@ -29,7 +29,7 @@ public class FakeInventoryActor : IInventoryActor, ITransientDependency return Task.CompletedTask; } - public Task ReduceInventoryAsync(int quantity, bool increaseSold) + public Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale) { StateModel.Inventory -= quantity; diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs index 7deb1fe6..a8f718d9 100644 --- a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs @@ -7,7 +7,7 @@ public interface IInventoryGrain : IGrainWithStringKey { Task GetInventoryStateAsync(); - Task IncreaseInventoryAsync(int quantity, bool decreaseSold); + Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale); - Task ReduceInventoryAsync(int quantity, bool increaseSold); + Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale); } \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj index 6e831f2a..2346d462 100644 --- a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj @@ -12,6 +12,7 @@ + all diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs index 087bb7b9..40b6f09d 100644 --- a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs @@ -1,8 +1,10 @@ using Volo.Abp.Modularity; +using Volo.Abp.Timing; namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; [DependsOn( + typeof(AbpTimingModule), typeof(EShopPluginsInventoriesOrleansGrainsAbstractionsModule) )] public class EShopPluginsInventoriesOrleansGrainsModule : AbpModule diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs index 454fdb86..06213b69 100644 --- a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs @@ -1,7 +1,9 @@ +using System; using System.Threading.Tasks; using Orleans; using Orleans.Providers; using Orleans.Runtime; +using Volo.Abp.Timing; namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; @@ -10,20 +12,66 @@ public class InventoryGrain : Grain, IInventoryGrain { public const string StorageProviderName = "EShopInventoryStorage"; - public virtual Task GetInventoryStateAsync() => Task.FromResult(State); + protected DateTime? TimeToPersistInventory { get; set; } - public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold) + protected IClock Clock { get; } + + public InventoryGrain(IClock clock) + { + Clock = clock; + } + + public virtual async Task GetInventoryStateAsync() + { + var state = State; + + await TryWriteStateAsync(); + + return state; + } + + public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale) { InternalIncreaseInventory(quantity, decreaseSold); - await WriteStateAsync(); + if (!isFlashSale || State.Inventory == 0) + { + await WriteStateAsync(); + } + else + { + TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30); + + await TryWriteStateAsync(); + } } - public async Task ReduceInventoryAsync(int quantity, bool increaseSold) + public virtual async Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale) { InternalReduceInventory(quantity, increaseSold); + if (!isFlashSale || State.Inventory == 0) + { + await WriteStateAsync(); + } + else + { + TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30); + + await TryWriteStateAsync(); + } + } + + public async Task TryWriteStateAsync() + { + if (!TimeToPersistInventory.HasValue || TimeToPersistInventory.Value < Clock.Now) + { + return false; + } + await WriteStateAsync(); + + return true; } protected virtual void InternalIncreaseInventory(int quantity, bool decreaseSold) diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs index b2b82346..f87b08d9 100644 --- a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs @@ -55,13 +55,13 @@ public class OrleansGrainsProductInventoryProvider : IProductInventoryProvider, } public virtual async Task TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, - bool decreaseSold) + bool decreaseSold, bool isFlashSale = false) { var grain = await GetGrainAsync(model); try { - await grain.IncreaseInventoryAsync(quantity, decreaseSold); + await grain.IncreaseInventoryAsync(quantity, decreaseSold, isFlashSale); } catch (Exception e) { @@ -73,7 +73,8 @@ public class OrleansGrainsProductInventoryProvider : IProductInventoryProvider, return true; } - public virtual async Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold) + public virtual async Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold, + bool isFlashSale = false) { var grain = await GetGrainAsync(model); @@ -86,7 +87,7 @@ public class OrleansGrainsProductInventoryProvider : IProductInventoryProvider, try { - await grain.ReduceInventoryAsync(quantity, increaseSold); + await grain.ReduceInventoryAsync(quantity, increaseSold, isFlashSale); } catch (Exception e) { diff --git a/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs index 49f7199a..3520d7a3 100644 --- a/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs +++ b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs @@ -17,7 +17,7 @@ public class FakeInventoryGrain : IInventoryGrain, ITransientDependency return Task.FromResult(StateModel); } - public Task IncreaseInventoryAsync(int quantity, bool decreaseSold) + public Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale) { StateModel.Inventory += quantity; @@ -29,7 +29,7 @@ public class FakeInventoryGrain : IInventoryGrain, ITransientDependency return Task.CompletedTask; } - public Task ReduceInventoryAsync(int quantity, bool increaseSold) + public Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale) { StateModel.Inventory -= quantity;