Browse Source

`DefaultProductInventoryProvider` using `DistributedLock`

pull/184/head
Jadyn 4 years ago
parent
commit
6cc239b8f2
  1. 1
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp.EShop.Products.Domain.csproj
  2. 41
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs

1
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp.EShop.Products.Domain.csproj

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.*" />
<PackageReference Include="NodaMoney" Version="$(NodaMoneyVersion)" />
<PackageReference Include="EasyAbp.Abp.Trees.Domain" Version="$(EasyAbpAbpTreesModuleVersion)" />
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(AbpVersion)" />

41
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Domain/EasyAbp/EShop/Products/Products/DefaultProductInventoryProvider.cs

@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.ProductInventories;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DistributedLocking;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
@ -13,6 +15,14 @@ namespace EasyAbp.EShop.Products.Products
{
public class DefaultProductInventoryProvider : IProductInventoryProvider, ITransientDependency
{
/// <summary>
/// The <see cref="GetLockKeyAsync(InventoryQueryModel)"/> lock key format.
/// <para>{0}: Tenant ID</para>
/// <para>{1}: Product ID</para>
/// <para>{2}: ProductSku ID</para>
/// </summary>
public const string DefaultProductInventoryLockKeyFormat = "eshop-product-inventory-{0}-{1}-{2}";
public static string DefaultProductInventoryProviderName { get; set; } = "Default";
public static string DefaultProductInventoryProviderDisplayName { get; set; } = "Default";
public static string DefaultProductInventoryProviderDescription { get; set; } = "Default";
@ -24,17 +34,23 @@ namespace EasyAbp.EShop.Products.Products
private readonly ICurrentTenant _currentTenant;
private readonly IDistributedEventBus _distributedEventBus;
private readonly IProductInventoryRepository _productInventoryRepository;
private readonly IAbpDistributedLock _distributedLock;
private readonly ILogger<DefaultProductInventoryProvider> _logger;
public DefaultProductInventoryProvider(
IGuidGenerator guidGenerator,
ICurrentTenant currentTenant,
IDistributedEventBus distributedEventBus,
IProductInventoryRepository productInventoryRepository)
IProductInventoryRepository productInventoryRepository,
IAbpDistributedLock distributedLock,
ILogger<DefaultProductInventoryProvider> logger)
{
_guidGenerator = guidGenerator;
_currentTenant = currentTenant;
_distributedEventBus = distributedEventBus;
_productInventoryRepository = productInventoryRepository;
_distributedLock = distributedLock;
_logger = logger;
}
[UnitOfWork]
@ -62,6 +78,15 @@ namespace EasyAbp.EShop.Products.Products
public virtual async Task<bool> TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity,
bool decreaseSold)
{
await using var handle = await _distributedLock.TryAcquireAsync(await GetLockKeyAsync(model), TimeSpan.FromSeconds(30));
if (handle == null)
{
_logger.LogWarning("TryIncreaseInventory failed to acquire lock for product inventory: {TenantId},{ProductId},{ProductSkuId}",
model.TenantId, model.ProductId, model.ProductSkuId);
return false;
}
var productInventory = await GetOrCreateProductInventoryAsync(model.ProductId, model.ProductSkuId);
return await TryIncreaseInventoryAsync(model, productInventory, quantity, decreaseSold);
@ -71,6 +96,15 @@ namespace EasyAbp.EShop.Products.Products
public virtual async Task<bool> TryReduceInventoryAsync(InventoryQueryModel model, int quantity,
bool increaseSold)
{
await using var handle = await _distributedLock.TryAcquireAsync(await GetLockKeyAsync(model), TimeSpan.FromSeconds(30));
if (handle == null)
{
_logger.LogWarning("TryReduceInventory failed to acquire lock for product inventory: {TenantId},{ProductId},{ProductSkuId}",
model.TenantId, model.ProductId, model.ProductSkuId);
return false;
}
var productInventory = await GetOrCreateProductInventoryAsync(model.ProductId, model.ProductSkuId);
return await TryReduceInventoryAsync(model, productInventory, quantity, increaseSold);
@ -158,5 +192,10 @@ namespace EasyAbp.EShop.Products.Products
newInventory,
sold));
}
protected virtual Task<string> GetLockKeyAsync(InventoryQueryModel model)
{
return Task.FromResult(string.Format(DefaultProductInventoryLockKeyFormat, model.TenantId, model.ProductId, model.ProductSkuId));
}
}
}
Loading…
Cancel
Save