Browse Source

Merge pull request #204 from EasyAbp/actor-delay-saving

Inventory actor/grain delay saving to the persistence
pull/205/head
Super 4 years ago
committed by GitHub
parent
commit
d171e11924
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain.Shared/EasyAbp/EShop/Products/ProductInventories/IProductInventoryProvider.cs
  2. 4
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs
  3. 8
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/ProductManager.cs
  4. 10
      modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.TestBase/FakeProductInventoryProvider.cs
  5. 18
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/FlashSaleInventoryManager.cs
  6. 8
      plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Abstractions/EasyAbp/Eshop/Products/Products/IFlashSaleInventoryManager.cs
  7. 4
      plugins/FlashSales/src/EasyAbp.EShop.Products.Plugins.FlashSales.Application/EasyAbp/EShop/Products/Products/LocalFlashSaleInventoryManager.cs
  8. 10
      plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeFlashSaleInventoryManager.cs
  9. 4
      plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors.Abstractions/EasyAbp/EShop/Plugins/Inventories/DaprActors/IInventoryActor.cs
  10. 1
      plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp.EShop.Plugins.Inventories.DaprActors.csproj
  11. 2
      plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/EShopPluginsInventoriesDaprActorsModule.cs
  12. 60
      plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/InventoryActor.cs
  13. 9
      plugins/Inventories/DaprActors/src/EasyAbp.EShop.Products.DaprActorsInventory.Domain/EasyAbp/EShop/Products/DaprActorsInventory/DaprActorsProductInventoryProvider.cs
  14. 4
      plugins/Inventories/DaprActors/test/EasyAbp.EShop.Products.DaprActorsInventory.Domain.Tests/FakeInventoryActor.cs
  15. 4
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs
  16. 1
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj
  17. 2
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs
  18. 56
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs
  19. 9
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs
  20. 4
      plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs

6
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<Dictionary<Guid, InventoryDataModel>> GetSkuIdInventoryDataMappingAsync(IList<InventoryQueryModel> models); Task<Dictionary<Guid, InventoryDataModel>> GetSkuIdInventoryDataMappingAsync(IList<InventoryQueryModel> models);
Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, bool decreaseSold); Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, bool decreaseSold,
bool isFlashSale = false);
Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold); Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold,
bool isFlashSale = false);
} }
} }

4
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)] [UnitOfWork(true)]
public virtual async Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, public virtual async Task<bool> 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)); await using var handle = await _distributedLock.TryAcquireAsync(await GetLockKeyAsync(model), TimeSpan.FromSeconds(30));
@ -94,7 +94,7 @@ namespace EasyAbp.EShop.Products.Products
[UnitOfWork(true)] [UnitOfWork(true)]
public virtual async Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, public virtual async Task<bool> 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)); await using var handle = await _distributedLock.TryAcquireAsync(await GetLockKeyAsync(model), TimeSpan.FromSeconds(30));

8
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 model = new InventoryQueryModel(product.TenantId, product.StoreId, product.Id, productSku.Id);
var isFlashSale = product.InventoryStrategy is InventoryStrategy.FlashSales;
return await (await _productInventoryProviderResolver.GetAsync(product)) return await (await _productInventoryProviderResolver.GetAsync(product))
.TryIncreaseInventoryAsync(model, quantity, reduceSold); .TryIncreaseInventoryAsync(model, quantity, reduceSold, isFlashSale);
} }
public virtual async Task<bool> TryReduceInventoryAsync(Product product, ProductSku productSku, int quantity, public virtual async Task<bool> 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 model = new InventoryQueryModel(product.TenantId, product.StoreId, product.Id, productSku.Id);
var isFlashSale = product.InventoryStrategy is InventoryStrategy.FlashSales;
return await (await _productInventoryProviderResolver.GetAsync(product)) return await (await _productInventoryProviderResolver.GetAsync(product))
.TryReduceInventoryAsync(model, quantity, increaseSold); .TryReduceInventoryAsync(model, quantity, increaseSold, isFlashSale);
} }
public virtual async Task<PriceDataModel> GetRealPriceAsync(Product product, ProductSku productSku) public virtual async Task<PriceDataModel> GetRealPriceAsync(Product product, ProductSku productSku)

10
modules/EasyAbp.EShop.Products/test/EasyAbp.EShop.Products.TestBase/FakeProductInventoryProvider.cs

@ -34,10 +34,11 @@ public class FakeProductInventoryProvider : IProductInventoryProvider, ITransien
return Task.FromResult(result); return Task.FromResult(result);
} }
public Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, bool decreaseSold) public Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, bool decreaseSold,
bool isFlashSale = false)
{ {
Model.Inventory++; Model.Inventory++;
if (decreaseSold) if (decreaseSold)
{ {
Model.Sold--; Model.Sold--;
@ -46,10 +47,11 @@ public class FakeProductInventoryProvider : IProductInventoryProvider, ITransien
return Task.FromResult(true); return Task.FromResult(true);
} }
public Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold) public Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold,
bool isFlashSale = false)
{ {
Model.Inventory--; Model.Inventory--;
if (increaseSold) if (increaseSold)
{ {
Model.Sold++; Model.Sold++;

18
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; FlashSaleInventoryReducerAppService = flashSaleInventoryReducerAppService;
} }
public virtual async Task<bool> TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, public virtual async Task<bool> TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId,
Guid productSkuId, int quantity, bool increaseSold) Guid productId, Guid productSkuId, int quantity, bool increaseSold)
{ {
return await FlashSaleInventoryReducerAppService.TryReduceAsync( return await FlashSaleInventoryReducerAppService.TryReduceAsync(new ReduceInventoryInput(
new ReduceInventoryInput(tenantId, providerName, storeId, productId, productSkuId, quantity, increaseSold)); tenantId, providerName, storeId, productId, productSkuId, quantity, increaseSold));
} }
public virtual async Task<bool> TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, public virtual async Task<bool> TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId,
Guid productSkuId, int quantity, bool decreaseSold) Guid productId, Guid productSkuId, int quantity, bool decreaseSold)
{ {
return await FlashSaleInventoryReducerAppService.TryIncreaseAsync return await FlashSaleInventoryReducerAppService.TryIncreaseAsync(new IncreaseInventoryInput(
(new IncreaseInventoryInput(tenantId, providerName, storeId, productId, productSkuId, quantity, decreaseSold)); tenantId, providerName, storeId, productId, productSkuId, quantity, decreaseSold));
} }
} }

8
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 public interface IFlashSaleInventoryManager
{ {
Task<bool> TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool increaseSold); Task<bool> TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId,
Guid productSkuId, int quantity, bool increaseSold);
Task<bool> TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool decreaseSold); Task<bool> TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId,
} Guid productSkuId, int quantity, bool decreaseSold);
}

4
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); var model = new InventoryQueryModel(tenantId, storeId, productId, productSkuId);
return await (await ProductInventoryProviderResolver.GetAsync(providerName)) return await (await ProductInventoryProviderResolver.GetAsync(providerName))
.TryReduceInventoryAsync(model, quantity, increaseSold); .TryReduceInventoryAsync(model, quantity, increaseSold, true);
} }
public virtual async Task<bool> TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId, public virtual async Task<bool> 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); var model = new InventoryQueryModel(tenantId, storeId, productId, productSkuId);
return await (await ProductInventoryProviderResolver.GetAsync(providerName)) return await (await ProductInventoryProviderResolver.GetAsync(providerName))
.TryIncreaseInventoryAsync(model, quantity, decreaseSold); .TryIncreaseInventoryAsync(model, quantity, decreaseSold, true);
} }
} }

10
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; ShouldReduceSuccess = true;
} }
public Task<bool> TryReduceInventoryAsync( public Task<bool> TryReduceInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId,
Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool increaseSold) Guid productSkuId, int quantity, bool increaseSold)
{ {
return Task.FromResult(ShouldReduceSuccess); return Task.FromResult(ShouldReduceSuccess);
} }
public Task<bool> TryRollBackInventoryAsync( public Task<bool> TryRollBackInventoryAsync(Guid? tenantId, string providerName, Guid storeId, Guid productId,
Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool decreaseSold) Guid productSkuId, int quantity, bool decreaseSold)
{ {
return Task.FromResult(true); return Task.FromResult(true);
} }
} }

4
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<InventoryStateModel> GetInventoryStateAsync(); Task<InventoryStateModel> 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);
} }

1
plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp.EShop.Plugins.Inventories.DaprActors.csproj

@ -12,6 +12,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.Timing" Version="$(AbpVersion)" />
<PackageReference Include="Dapr.Actors" Version="$(DaprSdkVersion)" /> <PackageReference Include="Dapr.Actors" Version="$(DaprSdkVersion)" />
</ItemGroup> </ItemGroup>

2
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.Modularity;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Plugins.Inventories.DaprActors; namespace EasyAbp.EShop.Plugins.Inventories.DaprActors;
[DependsOn( [DependsOn(
typeof(AbpTimingModule),
typeof(EShopPluginsInventoriesDaprActorsAbstractionsModule) typeof(EShopPluginsInventoriesDaprActorsAbstractionsModule)
)] )]
public class EShopPluginsInventoriesDaprActorsModule : AbpModule public class EShopPluginsInventoriesDaprActorsModule : AbpModule

60
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 System.Threading.Tasks;
using Dapr; using Dapr;
using Dapr.Actors.Runtime; using Dapr.Actors.Runtime;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Plugins.Inventories.DaprActors; namespace EasyAbp.EShop.Plugins.Inventories.DaprActors;
@ -8,8 +10,13 @@ public class InventoryActor : Actor, IInventoryActor
{ {
public static string InventoryStateName { get; set; } = "i"; 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() protected override async Task OnActivateAsync()
@ -19,25 +26,62 @@ public class InventoryActor : Actor, IInventoryActor
public virtual async Task<InventoryStateModel> GetInventoryStateAsync() public virtual async Task<InventoryStateModel> GetInventoryStateAsync()
{ {
return await StateManager.GetStateAsync<InventoryStateModel>(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); 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); 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<InventoryStateModel> InternalGetInventoryStateAsync() =>
StateManager.GetStateAsync<InventoryStateModel>(InventoryStateName);
public async Task<bool> TrySetInventoryStateAsync(InventoryStateModel stateModel)
{
if (!TimeToPersistInventory.HasValue || TimeToPersistInventory.Value < Clock.Now)
{
return false;
}
await SetInventoryStateAsync(stateModel);
return true;
} }
protected virtual async Task SetInventoryStateAsync(InventoryStateModel state) protected virtual async Task SetInventoryStateAsync(InventoryStateModel state)

9
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<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, public virtual async Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity,
bool decreaseSold) bool decreaseSold, bool isFlashSale = false)
{ {
var actor = await GetActorAsync(model); var actor = await GetActorAsync(model);
try try
{ {
await actor.IncreaseInventoryAsync(quantity, decreaseSold); await actor.IncreaseInventoryAsync(quantity, decreaseSold, isFlashSale);
} }
catch (Exception e) catch (Exception e)
{ {
@ -75,7 +75,8 @@ public class DaprActorsProductInventoryProvider : IProductInventoryProvider, ITr
return true; return true;
} }
public virtual async Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold) public virtual async Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold,
bool isFlashSale = false)
{ {
var actor = await GetActorAsync(model); var actor = await GetActorAsync(model);
@ -88,7 +89,7 @@ public class DaprActorsProductInventoryProvider : IProductInventoryProvider, ITr
try try
{ {
await actor.ReduceInventoryAsync(quantity, increaseSold); await actor.ReduceInventoryAsync(quantity, increaseSold, isFlashSale);
} }
catch (Exception e) catch (Exception e)
{ {

4
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); return Task.FromResult(StateModel);
} }
public Task IncreaseInventoryAsync(int quantity, bool decreaseSold) public Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale)
{ {
StateModel.Inventory += quantity; StateModel.Inventory += quantity;
@ -29,7 +29,7 @@ public class FakeInventoryActor : IInventoryActor, ITransientDependency
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task ReduceInventoryAsync(int quantity, bool increaseSold) public Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale)
{ {
StateModel.Inventory -= quantity; StateModel.Inventory -= quantity;

4
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<InventoryStateModel> GetInventoryStateAsync(); Task<InventoryStateModel> 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);
} }

1
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj

@ -12,6 +12,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.Timing" Version="$(AbpVersion)" />
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" Version="$(OrleansVersion)" /> <PackageReference Include="Microsoft.Orleans.Core.Abstractions" Version="$(OrleansVersion)" />
<PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="$(OrleansVersion)"> <PackageReference Include="Microsoft.Orleans.CodeGenerator.MSBuild" Version="$(OrleansVersion)">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

2
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.Modularity;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
[DependsOn( [DependsOn(
typeof(AbpTimingModule),
typeof(EShopPluginsInventoriesOrleansGrainsAbstractionsModule) typeof(EShopPluginsInventoriesOrleansGrainsAbstractionsModule)
)] )]
public class EShopPluginsInventoriesOrleansGrainsModule : AbpModule public class EShopPluginsInventoriesOrleansGrainsModule : AbpModule

56
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 System.Threading.Tasks;
using Orleans; using Orleans;
using Orleans.Providers; using Orleans.Providers;
using Orleans.Runtime; using Orleans.Runtime;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
@ -10,20 +12,66 @@ public class InventoryGrain : Grain<InventoryStateModel>, IInventoryGrain
{ {
public const string StorageProviderName = "EShopInventoryStorage"; public const string StorageProviderName = "EShopInventoryStorage";
public virtual Task<InventoryStateModel> 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<InventoryStateModel> GetInventoryStateAsync()
{
var state = State;
await TryWriteStateAsync();
return state;
}
public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale)
{ {
InternalIncreaseInventory(quantity, decreaseSold); 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); InternalReduceInventory(quantity, increaseSold);
if (!isFlashSale || State.Inventory == 0)
{
await WriteStateAsync();
}
else
{
TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30);
await TryWriteStateAsync();
}
}
public async Task<bool> TryWriteStateAsync()
{
if (!TimeToPersistInventory.HasValue || TimeToPersistInventory.Value < Clock.Now)
{
return false;
}
await WriteStateAsync(); await WriteStateAsync();
return true;
} }
protected virtual void InternalIncreaseInventory(int quantity, bool decreaseSold) protected virtual void InternalIncreaseInventory(int quantity, bool decreaseSold)

9
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<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, public virtual async Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity,
bool decreaseSold) bool decreaseSold, bool isFlashSale = false)
{ {
var grain = await GetGrainAsync(model); var grain = await GetGrainAsync(model);
try try
{ {
await grain.IncreaseInventoryAsync(quantity, decreaseSold); await grain.IncreaseInventoryAsync(quantity, decreaseSold, isFlashSale);
} }
catch (Exception e) catch (Exception e)
{ {
@ -73,7 +73,8 @@ public class OrleansGrainsProductInventoryProvider : IProductInventoryProvider,
return true; return true;
} }
public virtual async Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold) public virtual async Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold,
bool isFlashSale = false)
{ {
var grain = await GetGrainAsync(model); var grain = await GetGrainAsync(model);
@ -86,7 +87,7 @@ public class OrleansGrainsProductInventoryProvider : IProductInventoryProvider,
try try
{ {
await grain.ReduceInventoryAsync(quantity, increaseSold); await grain.ReduceInventoryAsync(quantity, increaseSold, isFlashSale);
} }
catch (Exception e) catch (Exception e)
{ {

4
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); return Task.FromResult(StateModel);
} }
public Task IncreaseInventoryAsync(int quantity, bool decreaseSold) public Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale)
{ {
StateModel.Inventory += quantity; StateModel.Inventory += quantity;
@ -29,7 +29,7 @@ public class FakeInventoryGrain : IInventoryGrain, ITransientDependency
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task ReduceInventoryAsync(int quantity, bool increaseSold) public Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale)
{ {
StateModel.Inventory -= quantity; StateModel.Inventory -= quantity;

Loading…
Cancel
Save