windows下使用redis解決.net6.0下人工呼叫介面時分配位置的併發問題

十四發表於2024-05-23

使用了nuget包包括了:CSRedisCore,StackExchange.Redis,MyStack.DistributedLocking,Microsoft.Extensions.Configuration

安裝Redis並註冊為windows服務 直接參考這位兄弟的成果:

https://www.cnblogs.com/qingheshiguang/p/17952623

註冊服務:

windows下使用redis解決.net6.0下人工呼叫介面時分配位置的併發問題
配置檔案appsetting.json中加上Redis的連線字串
 "Redis": "127.0.0.1:6379",

Program.cs中新增註冊服務
// 新增併發鎖支援
builder.Services.AddDistributedLock(builder.Configuration["Redis"]);
Program

windows下使用redis解決.net6.0下人工呼叫介面時分配位置的併發問題
using CSRedis;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Redis;
using Utility.Concurrent;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 新增併發鎖支援
        /// </summary>
        /// <param name="services"></param>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public static IServiceCollection AddDistributedLock(this IServiceCollection services, string connectionString)
        {
            RedisHelper.Initialization(new CSRedisClient(connectionString));
            services.AddSingleton<IDistributedCache>(new CSRedisCache(RedisHelper.Instance));
            services.AddSingleton(typeof(IDistributedLock), typeof(DistributedLock));
            return services;
        }
    }
}
View Code

redis客戶端實現

windows下使用redis解決.net6.0下人工呼叫介面時分配位置的併發問題
using CSRedis;

namespace Concurrent
{
    public class DistributedLock : IDistributedLock
    {
        private const string _lockKey = "LockKey";
        public async Task<bool> TryLockAsync(string key, int lockExpirySeconds = 10, long waitLockSeconds = 60)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException("鎖鍵值不能為空。");
            }

            DateTime begin = DateTime.Now;
            while (true)
            {
                if (await RedisHelper.SetAsync($"{_lockKey}.{key}", Thread.CurrentThread.ManagedThreadId, lockExpirySeconds, RedisExistence.Nx))
                {
                    return true;
                }
                //不等待鎖則返回
                if (waitLockSeconds == 0)
                {
                    break;
                }

                //超過等待時間,則不再等待
                if ((DateTime.Now - begin).TotalSeconds >= waitLockSeconds)
                {
                    break;
                }

                Thread.Sleep(100);
            }
            return false;
        }

        public async Task UnLockAsync(string key)
        {
            await RedisHelper.DelAsync($"{_lockKey}.{key}");
        }

        public async Task<T> LockExecuteAsync<T>(string key, Func<Task<T>> handle, int lockExpirySeconds = 10, long waitLockSeconds = 60)
        {
            if (await TryLockAsync(key, lockExpirySeconds, waitLockSeconds))
            {
                try
                {
                    return await handle?.Invoke();
                }
                finally
                {
                    try { await UnLockAsync(key); } finally { }
                }
            }
            return await Task.FromResult(default(T));
        }
    }
}
DistributedLock
    //鎖定分配的目標庫位
   var hasLock = await _distributedLock.TryLockAsync(LocationCode, 5, 10);
    if (!hasLock) 
    {
        throw new BizException(_Localizer["操作頻繁,稍後再試"]);
    }

業務中呼叫

相關文章