Browse Source

Merge pull request #206 from EasyAbp/actor-timer

Use actor timer to persist inventory for flash sales
pull/207/head
Super 4 years ago
committed by GitHub
parent
commit
5ecec12951
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp.EShop.Plugins.Inventories.DaprActors.csproj
  2. 2
      plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/EShopPluginsInventoriesDaprActorsModule.cs
  3. 59
      plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/InventoryActor.cs
  4. 1
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj
  5. 2
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs
  6. 47
      plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs

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

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

2
plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/EShopPluginsInventoriesDaprActorsModule.cs

@ -1,10 +1,8 @@
using Volo.Abp.Modularity;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Plugins.Inventories.DaprActors;
[DependsOn(
typeof(AbpTimingModule),
typeof(EShopPluginsInventoriesDaprActorsAbstractionsModule)
)]
public class EShopPluginsInventoriesDaprActorsModule : AbpModule

59
plugins/Inventories/DaprActors/src/EasyAbp.EShop.Plugins.Inventories.DaprActors/EasyAbp/EShop/Plugins/Inventories/DaprActors/InventoryActor.cs

@ -2,7 +2,7 @@ using System;
using System.Threading.Tasks;
using Dapr;
using Dapr.Actors.Runtime;
using Volo.Abp.Timing;
using JetBrains.Annotations;
namespace EasyAbp.EShop.Plugins.Inventories.DaprActors;
@ -10,13 +10,13 @@ public class InventoryActor : Actor, IInventoryActor
{
public static string InventoryStateName { get; set; } = "i";
protected DateTime? TimeToPersistInventory { get; set; }
protected bool FlashSalesInventoryUpdated { get; set; }
protected IClock Clock { get; }
[CanBeNull]
protected ActorTimer FlashSalesPersistInventoryTimer { get; set; }
public InventoryActor(ActorHost host, IClock clock) : base(host)
public InventoryActor(ActorHost host) : base(host)
{
Clock = clock;
}
protected override async Task OnActivateAsync()
@ -24,70 +24,67 @@ public class InventoryActor : Actor, IInventoryActor
await StateManager.TryAddStateAsync(InventoryStateName, new InventoryStateModel());
}
public virtual async Task<InventoryStateModel> GetInventoryStateAsync()
{
var state = await InternalGetInventoryStateAsync();
await TrySetInventoryStateAsync(state);
return state;
}
public virtual Task<InventoryStateModel> GetInventoryStateAsync() =>
StateManager.GetStateAsync<InventoryStateModel>(InventoryStateName);
public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale)
{
var state = await InternalGetInventoryStateAsync();
var state = await GetInventoryStateAsync();
InternalIncreaseInventory(state, quantity, decreaseSold);
if (!isFlashSale || state.Inventory == 0)
if (!isFlashSale)
{
await SetInventoryStateAsync(state);
}
else
{
TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30);
FlashSalesInventoryUpdated = true;
await TrySetInventoryStateAsync(state);
await TryRegisterFlashSalesPersistInventoryTimerAsync();
}
}
public virtual async Task ReduceInventoryAsync(int quantity, bool increaseSold, bool isFlashSale)
{
var state = await InternalGetInventoryStateAsync();
var state = await GetInventoryStateAsync();
InternalReduceInventory(state, quantity, increaseSold);
if (!isFlashSale || state.Inventory == 0)
if (!isFlashSale)
{
await SetInventoryStateAsync(state);
}
else
{
TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30);
FlashSalesInventoryUpdated = true;
await TrySetInventoryStateAsync(state);
await TryRegisterFlashSalesPersistInventoryTimerAsync();
}
}
protected virtual Task<InventoryStateModel> InternalGetInventoryStateAsync() =>
StateManager.GetStateAsync<InventoryStateModel>(InventoryStateName);
protected virtual async Task TryRegisterFlashSalesPersistInventoryTimerAsync()
{
FlashSalesPersistInventoryTimer ??= await RegisterTimerAsync(null, nameof(PeriodicSetInventoryStateAsync),
null, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(3));
}
protected virtual async Task<bool> TrySetInventoryStateAsync(InventoryStateModel stateModel)
protected virtual async Task PeriodicSetInventoryStateAsync()
{
if (!TimeToPersistInventory.HasValue || TimeToPersistInventory.Value < Clock.Now)
if (!FlashSalesInventoryUpdated)
{
return false;
return;
}
await SetInventoryStateAsync(stateModel);
await SetInventoryStateAsync(await GetInventoryStateAsync());
return true;
FlashSalesInventoryUpdated = false;
}
protected virtual async Task SetInventoryStateAsync(InventoryStateModel state)
{
protected virtual async Task SetInventoryStateAsync(InventoryStateModel state) =>
await StateManager.SetStateAsync(InventoryStateName, state);
}
protected override async Task OnDeactivateAsync() => await SetInventoryStateAsync(await GetInventoryStateAsync());
protected virtual void InternalIncreaseInventory(InventoryStateModel stateModel, int quantity, bool decreaseSold)
{

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

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

2
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs

@ -1,10 +1,8 @@
using Volo.Abp.Modularity;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
[DependsOn(
typeof(AbpTimingModule),
typeof(EShopPluginsInventoriesOrleansGrainsAbstractionsModule)
)]
public class EShopPluginsInventoriesOrleansGrainsModule : AbpModule

47
plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs

@ -1,9 +1,9 @@
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Orleans;
using Orleans.Providers;
using Orleans.Runtime;
using Volo.Abp.Timing;
namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains;
@ -12,23 +12,12 @@ public class InventoryGrain : Grain<InventoryStateModel>, IInventoryGrain
{
public const string StorageProviderName = "EShopInventoryStorage";
protected DateTime? TimeToPersistInventory { get; set; }
protected bool FlashSalesInventoryUpdated { get; set; }
protected IClock Clock { get; }
[CanBeNull]
protected IDisposable FlashSalesPersistInventoryTimer { get; set; }
public InventoryGrain(IClock clock)
{
Clock = clock;
}
public virtual async Task<InventoryStateModel> GetInventoryStateAsync()
{
var state = State;
await TryWriteStateAsync();
return state;
}
public virtual Task<InventoryStateModel> GetInventoryStateAsync() => Task.FromResult(State);
public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold, bool isFlashSale)
{
@ -40,9 +29,9 @@ public class InventoryGrain : Grain<InventoryStateModel>, IInventoryGrain
}
else
{
TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30);
FlashSalesInventoryUpdated = true;
await TryWriteStateAsync();
TryRegisterFlashSalesPersistInventoryTimer();
}
}
@ -56,24 +45,32 @@ public class InventoryGrain : Grain<InventoryStateModel>, IInventoryGrain
}
else
{
TimeToPersistInventory ??= Clock.Now + TimeSpan.FromSeconds(30);
FlashSalesInventoryUpdated = true;
await TryWriteStateAsync();
TryRegisterFlashSalesPersistInventoryTimer();
}
}
public async Task<bool> TryWriteStateAsync()
protected virtual void TryRegisterFlashSalesPersistInventoryTimer()
{
FlashSalesPersistInventoryTimer ??= RegisterTimer(PeriodicWriteInventoryStateAsync,
new object(), TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(3));
}
protected virtual async Task PeriodicWriteInventoryStateAsync(object obj)
{
if (!TimeToPersistInventory.HasValue || TimeToPersistInventory.Value < Clock.Now)
if (!FlashSalesInventoryUpdated)
{
return false;
return;
}
await WriteStateAsync();
return true;
FlashSalesInventoryUpdated = false;
}
public override Task OnDeactivateAsync() => WriteStateAsync();
protected virtual void InternalIncreaseInventory(int quantity, bool decreaseSold)
{
if (quantity < 0)

Loading…
Cancel
Save