فهرست منبع

20250110 打个标签,准备更新redis库

dodo hold 1 سال پیش
والد
کامیت
51cee1900c
46فایلهای تغییر یافته به همراه939 افزوده شده و 528 حذف شده
  1. 1 1
      molilian.api/Controllers/public/ApiController.cs
  2. 1 1
      molilian.api/Controllers/public/CpsController.cs
  3. 0 340
      molilian.api/Controllers/public/FeatureController.cs
  4. 90 0
      molilian.api/Controllers/public/NewController.cs
  5. 444 0
      molilian.api/Controllers/public/StressTestController.cs
  6. 13 13
      molilian.api/Controllers/public/TaskController.cs
  7. 1 1
      molilian.api/Controllers/public/TestController.cs
  8. 8 11
      molilian.api/Controllers/public/TkController.cs
  9. 3 3
      molilian.api/Dockerfile
  10. 2 1
      molilian.api/Properties/PublishProfiles/latest.pubxml
  11. 0 0
      molilian.api/Properties/PublishProfiles/latest.pubxml.user
  12. 0 0
      molilian.api/Properties/PublishProfiles/tester.pubxml.user
  13. 2 1
      molilian.api/molilian.api.csproj
  14. 9 7
      molilian.core/Core/API/ApiAccountCore.cs
  15. 13 11
      molilian.core/Core/EndPointCore.cs
  16. 3 0
      molilian.core/Core/aliyun/AliyunCore.cs
  17. 4 4
      molilian.core/Core/cps/CpsPoolCore.cs
  18. 2 2
      molilian.core/Core/cps/ElePoolCore.cs
  19. 2 2
      molilian.core/Core/cps/MeituanPoolCore.cs
  20. 2 1
      molilian.core/Core/cps/UnionCpsCore.cs
  21. 2 2
      molilian.core/Core/jd/JdPoolCore.cs
  22. 2 2
      molilian.core/Core/ks/KsPoolCore.cs
  23. 61 0
      molilian.core/Core/log/base.cs
  24. 2 2
      molilian.core/Core/log/coupon.cs
  25. 2 2
      molilian.core/Core/log/cps.cs
  26. 2 2
      molilian.core/Core/log/deeplink.cs
  27. 1 1
      molilian.core/Core/log/dy.cs
  28. 2 2
      molilian.core/Core/log/jd.cs
  29. 2 2
      molilian.core/Core/log/ks.cs
  30. 2 2
      molilian.core/Core/log/pdd.cs
  31. 2 2
      molilian.core/Core/log/taobao.cs
  32. 2 2
      molilian.core/Core/log/tool.cs
  33. 3 3
      molilian.core/Core/log/第三方旧接口.cs
  34. 2 2
      molilian.core/Core/pdd/PddPoolCore.cs
  35. 3 3
      molilian.core/Core/taoke/RiskControlCore.cs
  36. 19 19
      molilian.core/Core/taoke/TaokeOpenCore.cs
  37. 58 32
      molilian.core/Core/taoke/TkPoolCore.cs
  38. 1 1
      molilian.core/Core/taoke/UnionCouponCore.cs
  39. 26 26
      molilian.core/Core/taoke/UnionParseCore.cs
  40. 1 1
      molilian.core/Plus/Alimama/account.cs
  41. 4 4
      molilian.core/Plus/Alimama/crawler.cs
  42. 15 15
      molilian.core/Plus/Alimama/parse.cs
  43. 3 0
      molilian.core/Plus/Aliyun/ImageSearch.cs
  44. 111 0
      molilian.core/Plus/SystemMonitor.cs
  45. 10 1
      molilian.core/middleware/CustomToken.cs
  46. 1 1
      molilian.core/molilian.core.csproj

+ 1 - 1
molilian.api/Controllers/public/ApiController.cs

@@ -100,7 +100,7 @@ namespace molilian.api.Controllers
                 return new APIResult(new { success = false, message = "验证错误2" }, APIResultCodeEnum.Unauthorized);
             }
 
-            var account = ApiAccountCore.GetOne(a);
+            var account = await ApiAccountCore.GetOneAsync(a);
             if (account == null)
             {
                 return new APIResult(new { success = false, message = "验证错误3" }, APIResultCodeEnum.Unauthorized);

+ 1 - 1
molilian.api/Controllers/public/CpsController.cs

@@ -58,7 +58,7 @@ namespace molilian.api.Controllers
                 return new APIResult(new { success = false, message = "验证错误2" }, APIResultCodeEnum.Unauthorized);
             }
 
-            var account = ApiAccountCore.GetOne(a);
+            var account = await ApiAccountCore.GetOneAsync(a);
             if (account == null)
             {
                 return new APIResult(new { success = false, message = "验证错误3" }, APIResultCodeEnum.Unauthorized);

+ 0 - 340
molilian.api/Controllers/public/FeatureController.cs

@@ -1,340 +0,0 @@
-using molilian.core;
-using dodohold.core;
-using Microsoft.AspNetCore.Mvc;
-using System.Text;
-using System.Text.Json;
-using System.Collections.Concurrent;
-using System.Diagnostics;
-namespace molilian.api.Controllers
-{
-
-    [ApiController]
-    [Route("[controller]/[action]")]
-    public class FeatureController : ControllerBase
-    {
-
-        protected IHttpContextAccessor _accessor;
-        public FeatureController(IHttpContextAccessor accessor)
-        {
-            _accessor = accessor;
-        }
-
-        [HttpGet]
-        public async Task<ActionResult> CSRedis(int thread, int durationSeconds = 30)
-        {
-            var watch = System.Diagnostics.Stopwatch.StartNew();
-            var cts = new CancellationTokenSource();
-            var performanceLogger = new RedisPerformanceLogger();
-
-            long totalRequests = 0;
-            long successCount = 0;
-            long failureCount = 0;
-
-            var metricsQueue = new ConcurrentQueue<RedisOperationMetrics>();
-
-            var tasks = new List<Task>();
-            for (int i = 0; i < thread; i++)
-            {
-                tasks.Add(Task.Run(() =>
-                {
-                    while (!cts.Token.IsCancellationRequested)
-                    {
-                        var metrics = new RedisOperationMetrics();
-                        try
-                        {
-                            // 写入操作
-                            var sw = Stopwatch.StartNew();
-                            var testValue = "test value";
-                            var key = $"test:csredis:{Guid.NewGuid()}";
-                            RedisHelper.Set(key, testValue, 60);
-                            sw.Stop();
-                            metrics.WriteTimeMs = sw.ElapsedMilliseconds;
-                            metrics.KeySize = Encoding.UTF8.GetByteCount(key);
-                            metrics.ValueSize = Encoding.UTF8.GetByteCount(testValue);
-
-                            // IncrBy操作
-                            sw.Restart();
-                            RedisHelper.IncrBy("counter:csredis", 1);
-                            sw.Stop();
-                            metrics.IncrByTimeMs = sw.ElapsedMilliseconds;
-
-                            // 读取操作
-                            sw.Restart();
-                            var value = RedisHelper.Get("counter:csredis");
-                            sw.Stop();
-                            metrics.ReadTimeMs = sw.ElapsedMilliseconds;
-
-                            metrics.IsSuccess = true;
-                            Interlocked.Increment(ref successCount);
-                        }
-                        catch (Exception ex)
-                        {
-                            metrics.IsSuccess = false;
-                            metrics.ErrorMessage = ex.Message;
-                            Interlocked.Increment(ref failureCount);
-
-                            string message = $"{ex.Message}\n{ex.StackTrace}";
-                            NotifyCore.Notify(new NifyMessage
-                            {
-                                message = message,
-                                priority = NifyMessagePriority.high,
-                                tags = ["red_circle"]
-                            });
-                            new LoggerLibrary("Feature").Info(message).SaveAsync();
-                        }
-                        finally
-                        {
-                            metricsQueue.Enqueue(metrics);
-                            Interlocked.Increment(ref totalRequests);
-                        }
-                    }
-                }, cts.Token));
-            }
-
-            await Task.Delay(TimeSpan.FromSeconds(durationSeconds));
-            cts.Cancel();
-
-            try
-            {
-                await Task.WhenAll(tasks);
-            }
-            catch (OperationCanceledException)
-            {
-                // 预期的取消异常
-            }
-
-            watch.Stop();
-            var elapsedMs = watch.ElapsedMilliseconds;
-            var qps = totalRequests * 1000.0 / elapsedMs;
-
-            var metrics = metricsQueue.ToList();
-            var writeStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.WriteTimeMs);
-            var incrByStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.IncrByTimeMs);
-            var readStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.ReadTimeMs);
-
-            var resultData = new Dictionary<string, object>
-            {
-                ["ConcurrentThreads"] = thread,
-                ["DurationSeconds"] = durationSeconds,
-                ["TotalTimeMs"] = elapsedMs,
-                ["TotalRequests"] = totalRequests,
-                ["SuccessCount"] = successCount,
-                ["FailureCount"] = failureCount,
-                ["QPS"] = Math.Round(qps, 2),
-                ["SuccessRate"] = Math.Round((double)successCount / totalRequests * 100, 2),
-                ["RedisMetrics"] = new
-                {
-                    Write = writeStats,
-                    IncrBy = incrByStats,
-                    Read = readStats
-                }
-            };
-
-            await performanceLogger.LogPerformanceResult("CSRedis", resultData);
-
-            return new APIResult(resultData);
-        }
-
-        [HttpGet]
-        public async Task<ActionResult> FreeRedis(int thread, int durationSeconds = 30)
-        {
-            var watch = System.Diagnostics.Stopwatch.StartNew();
-            var cts = new CancellationTokenSource();
-            var performanceLogger = new RedisPerformanceLogger();
-
-            long totalRequests = 0;
-            long successCount = 0;
-            long failureCount = 0;
-
-            var metricsQueue = new ConcurrentQueue<RedisOperationMetrics>();
-            var redis = YunhuiKit.RedisKit.Instance;
-
-            var tasks = new List<Task>();
-            for (int i = 0; i < thread; i++)
-            {
-                tasks.Add(Task.Run(() =>
-                {
-                    while (!cts.Token.IsCancellationRequested)
-                    {
-                        var metrics = new RedisOperationMetrics();
-                        try
-                        {
-                            // 写入操作
-                            var sw = Stopwatch.StartNew();
-                            var testValue = "test value";
-                            var key = $"test:freeredis:{Guid.NewGuid()}";
-                            redis.Set(key, testValue, 60);
-                            sw.Stop();
-                            metrics.WriteTimeMs = sw.ElapsedMilliseconds;
-                            metrics.KeySize = Encoding.UTF8.GetByteCount(key);
-                            metrics.ValueSize = Encoding.UTF8.GetByteCount(testValue);
-
-                            // IncrBy操作
-                            sw.Restart();
-                            redis.IncrBy("counter:freeredis", 1);
-                            sw.Stop();
-                            metrics.IncrByTimeMs = sw.ElapsedMilliseconds;
-
-                            // 读取操作
-                            sw.Restart();
-                            var value = redis.Get("counter:freeredis");
-                            sw.Stop();
-                            metrics.ReadTimeMs = sw.ElapsedMilliseconds;
-
-                            metrics.IsSuccess = true;
-                            Interlocked.Increment(ref successCount);
-                        }
-                        catch (Exception ex)
-                        {
-                            metrics.IsSuccess = false;
-                            metrics.ErrorMessage = ex.Message;
-                            Interlocked.Increment(ref failureCount);
-
-                            string message = $"{ex.Message}\n{ex.StackTrace}";
-                            NotifyCore.Notify(new NifyMessage
-                            {
-                                message = message,
-                                priority = NifyMessagePriority.high,
-                                tags = ["red_circle"]
-                            });
-                            new LoggerLibrary("Feature").Info(message).SaveAsync();
-                        }
-                        finally
-                        {
-                            metricsQueue.Enqueue(metrics);
-                            Interlocked.Increment(ref totalRequests);
-                        }
-                    }
-                }, cts.Token));
-            }
-
-            await Task.Delay(TimeSpan.FromSeconds(durationSeconds));
-            cts.Cancel();
-
-            try
-            {
-                await Task.WhenAll(tasks);
-            }
-            catch (OperationCanceledException)
-            {
-                // 预期的取消异常
-            }
-
-            watch.Stop();
-            var elapsedMs = watch.ElapsedMilliseconds;
-            var qps = totalRequests * 1000.0 / elapsedMs;
-
-            var metrics = metricsQueue.ToList();
-            var writeStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.WriteTimeMs);
-            var incrByStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.IncrByTimeMs);
-            var readStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.ReadTimeMs);
-
-            var resultData = new Dictionary<string, object>
-            {
-                ["ConcurrentThreads"] = thread,
-                ["DurationSeconds"] = durationSeconds,
-                ["TotalTimeMs"] = elapsedMs,
-                ["TotalRequests"] = totalRequests,
-                ["SuccessCount"] = successCount,
-                ["FailureCount"] = failureCount,
-                ["QPS"] = Math.Round(qps, 2),
-                ["SuccessRate"] = Math.Round((double)successCount / totalRequests * 100, 2),
-                ["RedisMetrics"] = new
-                {
-                    Write = writeStats,
-                    IncrBy = incrByStats,
-                    Read = readStats
-                }
-            };
-
-            await performanceLogger.LogPerformanceResult("FreeRedis", resultData);
-
-            return new APIResult(resultData);
-
-        }
-    }
-
-
-    public class RedisPerformanceLogger
-    {
-        private readonly LoggerLibrary _logger;
-        private const string LoggerName = "RedisPerformance";
-
-        public RedisPerformanceLogger()
-        {
-            _logger = new LoggerLibrary(LoggerName);
-        }
-
-        public async Task LogPerformanceResult(string clientType, Dictionary<string, object> metrics)
-        {
-            var logMessage = new StringBuilder();
-            logMessage.AppendLine($"Redis Performance Test Result - {clientType}");
-            logMessage.AppendLine($"DateTime: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
-
-            foreach (var kvp in metrics)
-            {
-                logMessage.AppendLine($"{kvp.Key}: {JsonSerializer.Serialize(kvp.Value, new JsonSerializerOptions
-                {
-                    WriteIndented = true
-                })}");
-            }
-
-            await _logger.Info(logMessage.ToString()).SaveAsync();
-        }
-    }
-
-
-    public class RedisOperationMetrics
-    {
-        public long WriteTimeMs { get; set; }
-        public long IncrByTimeMs { get; set; }
-        public long ReadTimeMs { get; set; }
-        public DateTime OperationTime { get; set; } = DateTime.Now;
-        public string OperationType { get; set; }
-        public bool IsSuccess { get; set; }
-        public string ErrorMessage { get; set; }
-        public int RetryCount { get; set; }
-        public long KeySize { get; set; }
-        public long ValueSize { get; set; }
-
-        public static double CalculatePercentile(List<long> times, double percentile)
-        {
-            if (times == null || times.Count == 0) return 0;
-
-            var sortedTimes = times.OrderBy(t => t).ToList();
-            var index = (int)Math.Ceiling(percentile / 100.0 * sortedTimes.Count) - 1;
-            return sortedTimes[Math.Max(0, index)];
-        }
-
-        public static OperationStatistics CalculateStatistics(IEnumerable<RedisOperationMetrics> metrics, Func<RedisOperationMetrics, long> timeSelector)
-        {
-            var times = metrics.Select(timeSelector).ToList();
-
-            return new OperationStatistics
-            {
-                Average = times.Any() ? Math.Round(times.Average(), 2) : 0,
-                Median = CalculatePercentile(times, 50),
-                P95 = CalculatePercentile(times, 95),
-                P99 = CalculatePercentile(times, 99),
-                Max = times.Any() ? times.Max() : 0,
-                Min = times.Any() ? times.Min() : 0,
-                Count = times.Count,
-                TotalTime = times.Sum()
-            };
-        }
-    }
-
-    public class OperationStatistics
-    {
-        public double Average { get; set; }
-        public double Median { get; set; }
-        public double P95 { get; set; }
-        public double P99 { get; set; }
-        public long Max { get; set; }
-        public long Min { get; set; }
-        public int Count { get; set; }
-        public long TotalTime { get; set; }
-    }
-
-
-}

+ 90 - 0
molilian.api/Controllers/public/NewController.cs

@@ -0,0 +1,90 @@
+using molilian.core;
+using dodohold.core;
+using Microsoft.AspNetCore.Mvc;
+using Org.BouncyCastle.Ocsp;
+using System.Text.Json;
+using System.Runtime.InteropServices;
+using System.Net;
+using System.Threading;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using TencentCloud.Soe.V20180724.Models;
+using static dodohold.core.ZTOExpress.CreateOrderArgs;
+using static Spire.Xls.Core.Spreadsheet.HTMLOptions;
+using System.Net.Http.Json;
+using System.Text.RegularExpressions;
+using System.Text;
+using TencentCloud.Oceanus.V20190422.Models;
+using System.Security.Cryptography;
+using YunhuiKit;
+using System.Diagnostics;
+
+namespace molilian.api.Controllers
+{
+    [ApiController]
+    [Route("[controller]/[action]")]
+    public class NewController : ControllerBase
+    {
+
+        protected IHttpContextAccessor _accessor;
+        public NewController(IHttpContextAccessor accessor)
+        {
+            _accessor = accessor;
+        }
+
+
+        [HttpGet]
+        public async Task<ActionResult> redis()
+        {
+
+            var result = AlimamaPlus.GetFormattedObject("中国1@#阿斯蒂芬", "127.0.0.1", "0000-00-0000");
+
+            string cacheKey = "tmp:test:case1";
+            RedisHelper.Set(cacheKey, result, 300);
+            var data1 = RedisHelper.Get<TkDataDTO>(cacheKey);
+            var data2 = await RedisKit.GetAsync<TkDataDTO>(cacheKey);
+
+            await RedisKit.SetAsync(cacheKey, result, 300);
+            data1 = RedisHelper.Get<TkDataDTO>(cacheKey);
+            data2 = await RedisKit.GetAsync<TkDataDTO>(cacheKey);
+
+
+            await RedisKit.SetAsync(cacheKey, "a", 300);
+            var data3 = RedisHelper.Get<int>(cacheKey);
+            var data4 = await RedisKit.GetAsync<int>(cacheKey);
+
+
+            return new APIResult(new { data = new List<TkDataDTO> { data1, data2 } });
+        }
+
+
+
+        [HttpGet]
+        public async Task<ActionResult> redis2(int count = 100)
+        {
+            var stopwatch = new Stopwatch();
+            stopwatch.Start();
+            // 执行100次
+            for (int i = 0; i < 100; i++)
+            {
+                int total_count = TkLogCore.GetTotal($":total:tb:2025-01-09");
+            }
+            stopwatch.Stop();
+
+            var stopwatch2 = new Stopwatch();
+            stopwatch2.Start();
+            // 执行100次
+            for (int i = 0; i < 100; i++)
+            {
+                int total_count = await TkLogCore.GetTotalAsync($":total:tb:2025-01-09");
+            }
+            stopwatch2.Stop();
+            return new APIResult(new
+            {
+                ts = stopwatch.ElapsedMilliseconds,
+                ts2 = stopwatch2.ElapsedMilliseconds,
+            });
+
+        }
+
+    }
+}

+ 444 - 0
molilian.api/Controllers/public/StressTestController.cs

@@ -0,0 +1,444 @@
+using CSRedis;
+using dodohold.core;
+using ICSharpCode.SharpZipLib.Zip;
+using Microsoft.AspNetCore.Mvc;
+using System.Diagnostics;
+using System.Text;
+using System.Text.Json.Serialization;
+
+namespace molilian.api.Controllers
+{
+    [ApiController]
+    [Route("api/[controller]")]
+    public class StressTestController : ControllerBase
+    {
+        private static readonly StressTestService _stressTestService = new();
+
+
+        [HttpPost("start")]
+        public IActionResult StartTest([FromBody] StressTestConfig config)
+        {
+            _stressTestService.StartTest(config);
+            return Ok(new { message = "压力测试已启动" });
+        }
+
+        [HttpPost("stop")]
+        public IActionResult StopTest()
+        {
+            _stressTestService.StopTest();
+            return Ok(new { message = "压力测试已停止" });
+        }
+
+        [HttpGet("status")]
+        public IActionResult GetStatus()
+        {
+            return Ok(_stressTestService.GetStatus());
+        }
+
+        // StressTestController.cs 中 GetMetrics 方法的修改
+        [HttpGet("metrics")]
+        public IActionResult GetMetrics()
+        {
+            var status = _stressTestService.GetStatus();
+            return Ok(new
+            {
+                每秒总操作数 = status.LastSecondOperations,
+                每秒读操作数 = status.LastSecondReads,
+                每秒写操作数 = status.LastSecondWrites,
+                数据吞吐量 = status.FormattedThroughput,
+                平均响应时间 = status.AverageResponseTime
+            });
+        }
+
+
+    }
+
+    // StressTestService.cs
+    public class StressTestService
+    {
+        private CancellationTokenSource _cancellationTokenSource;
+        private TestStatus _status = new TestStatus();
+        private readonly object _lockObject = new object();
+        private volatile int _currentConcurrentTasks;  // 当前并发数
+        private List<Task> _runningTasks;             // 正在运行的任务列表
+
+        // 计数器字段
+        private int _timeoutCount;
+        private int _errorCount;
+        private int _completedRequests;
+        private long _totalResponseTime;
+
+        private int _readCount;  // 添加读操作计数
+        private int _writeCount; // 添加写操作计数
+
+        private string _testValue; // 缓存生成的测试数据
+        private readonly Random _random = new Random();
+
+
+        private int _lastSecondReads;
+        private int _lastSecondWrites;
+        private DateTime _lastCounterReset = DateTime.Now;
+
+        private volatile StressTestConfig _currentConfig;  // 添加当前配置字段
+
+
+        private async Task ManageTasks(CancellationToken cancellationToken)
+        {
+            _runningTasks = new List<Task>();
+
+            while (!cancellationToken.IsCancellationRequested)
+            {
+                try
+                {
+                    // 移除已完成的任务
+                    _runningTasks.RemoveAll(t => t.IsCompleted || t.IsFaulted || t.IsCanceled);
+
+                    // 获取当前配置的目标并发数
+                    int targetConcurrency = _currentConfig.ConcurrentTasks;
+
+                    // 增加任务
+                    while (_runningTasks.Count < targetConcurrency)
+                    {
+                        var taskId = _runningTasks.Count;
+                        var task = RunSingleTask(taskId, cancellationToken);
+                        _runningTasks.Add(task);
+                        Console.WriteLine($"添加新任务,当前任务数:{_runningTasks.Count}");
+                    }
+
+                    // 减少任务
+                    while (_runningTasks.Count > targetConcurrency)
+                    {
+                        int removeCount = _runningTasks.Count - targetConcurrency;
+                        Console.WriteLine($"移除{removeCount}个任务");
+
+                        // 移除多余的任务
+                        _runningTasks.RemoveRange(targetConcurrency, removeCount);
+                    }
+
+                    await Task.Delay(1000, cancellationToken); // 每秒检查一次任务状态
+                }
+                catch (OperationCanceledException)
+                {
+                    // 正常的取消操作
+                    break;
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine($"任务管理异常:{ex.Message}");
+                    // 继续运行,不要因为单次异常而停止整个测试
+                }
+            }
+        }
+
+        public void StartTest(StressTestConfig config)
+        {
+            lock (_lockObject)
+            {
+                // 更新配置
+                _currentConfig = config;
+
+                if (_status.IsRunning)
+                {
+                    Console.WriteLine($"更新配置 - 并发数: {config.ConcurrentTasks}, 读写比: {config.ReadsPerWrite}, 数据大小: {config.ValueSizeKB}KB");
+                    _status.CurrentConfig = config;
+                    return;
+                }
+
+                // 首次启动
+                Console.WriteLine($"启动测试 - 并发数: {config.ConcurrentTasks}, 读写比: {config.ReadsPerWrite}, 数据大小: {config.ValueSizeKB}KB");
+
+                _timeoutCount = 0;
+                _errorCount = 0;
+                _completedRequests = 0;
+                _totalResponseTime = 0;
+                _readCount = 0;
+                _writeCount = 0;
+                _totalDataSize = 0;
+
+                _cancellationTokenSource = new CancellationTokenSource();
+                _status = new TestStatus
+                {
+                    IsRunning = true,
+                    StartTime = DateTime.Now,
+                    CurrentConfig = config,
+                    EndTime = DateTime.Now.AddHours(1)
+                };
+
+                // 启动任务管理器
+                Task.Run(() => ManageTasks(_cancellationTokenSource.Token));
+            }
+        }
+
+
+
+        private async Task RunSingleTask(int taskId, CancellationToken cancellationToken)
+        {
+            var endTime = DateTime.Now.AddHours(1);
+            int requestId = 0;
+
+            while (DateTime.Now < endTime && !cancellationToken.IsCancellationRequested)
+            {
+                try
+                {
+                    // 获取最新配置
+                    var config = _currentConfig;
+                    var testValue = GenerateTestValue(config.ValueSizeKB);
+                    var key = $"test:key:{taskId}:{requestId++}";
+
+
+                    // 构造包含大小信息的值
+                    var value = new
+                    {
+                        id = $"{taskId}_{requestId}",
+                        timestamp = DateTime.Now.Ticks,
+                        data = testValue
+                    };
+
+                    // 写入操作
+                    try
+                    {
+                        var requestSw = Stopwatch.StartNew();
+                        var setTask = RedisHelper.SetAsync(key, value, 3600);
+                        var timeoutTask = Task.Delay(config.TimeoutMs);
+
+                        var completedTask = await Task.WhenAny(setTask, timeoutTask);
+                        if (completedTask == timeoutTask)
+                        {
+                            Interlocked.Increment(ref _timeoutCount);
+                            continue;
+                        }
+
+                        requestSw.Stop();
+                        Interlocked.Increment(ref _writeCount);
+                        Interlocked.Increment(ref _lastSecondWrites);
+                        Interlocked.Add(ref _totalResponseTime, requestSw.ElapsedMilliseconds);
+                        Interlocked.Add(ref _totalDataSize, config.ValueSizeKB * 1024);
+                        UpdateStatus();
+                    }
+                    catch (Exception)
+                    {
+                        Interlocked.Increment(ref _errorCount);
+                        continue;
+                    }
+
+                    // 执行多次读取操作,使用最新的配置
+                    for (int i = 0; i < config.ReadsPerWrite && !cancellationToken.IsCancellationRequested; i++)
+                    {
+                        try
+                        {
+                            var requestSw = Stopwatch.StartNew();
+                            var getTask = Task.Run(() =>
+                            {
+                                try
+                                {
+                                    RedisHelper.Get<object>(key);
+                                }
+                                catch (Exception)
+                                {
+                                    Interlocked.Increment(ref _errorCount);
+                                }
+                            });
+                            var timeoutTask = Task.Delay(config.TimeoutMs);
+
+                            var completedTask = await Task.WhenAny(getTask, timeoutTask);
+                            if (completedTask == timeoutTask)
+                            {
+                                Interlocked.Increment(ref _timeoutCount);
+                                continue;
+                            }
+
+                            requestSw.Stop();
+                            Interlocked.Increment(ref _readCount);
+                            Interlocked.Increment(ref _lastSecondReads);
+                            Interlocked.Add(ref _totalResponseTime, requestSw.ElapsedMilliseconds);
+                            Interlocked.Add(ref _totalDataSize, config.ValueSizeKB * 1024);
+                            UpdateStatus();
+
+                            if (config.OperationIntervalMs > 0)
+                            {
+                                await Task.Delay(config.OperationIntervalMs, cancellationToken);
+                            }
+                        }
+                        catch (Exception)
+                        {
+                            Interlocked.Increment(ref _errorCount);
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine($"任务 {taskId} 异常:{ex.Message}");
+                    Interlocked.Increment(ref _errorCount);
+
+                    // 添加短暂延迟,避免出错时立即重试
+                    await Task.Delay(100, cancellationToken);
+                }
+
+            }
+        }
+
+
+        // 生成指定大小的随机字符串
+        private string GenerateTestValue(int sizeKB)
+        {
+            if (_testValue != null && _testValue.Length == sizeKB * 1024) // 如果已有相同大小的数据,直接返回
+                return _testValue;
+
+            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+            var stringBuilder = new StringBuilder(sizeKB * 1024);
+
+            for (int i = 0; i < sizeKB * 1024; i++)
+            {
+                stringBuilder.Append(chars[_random.Next(chars.Length)]);
+            }
+
+            _testValue = stringBuilder.ToString();
+            return _testValue;
+        }
+
+
+        private long _totalDataSize; // 添加数据大小统计
+
+        private void UpdateStatus()
+        {
+            lock (_lockObject)
+            {
+                var now = DateTime.Now;
+                if ((now - _lastCounterReset).TotalSeconds >= 1)
+                {
+                    _status.LastSecondReads = _lastSecondReads;
+                    _status.LastSecondWrites = _lastSecondWrites;
+                    _status.LastSecondOperations = _lastSecondReads + _lastSecondWrites;
+
+                    _lastSecondReads = 0;
+                    _lastSecondWrites = 0;
+                    _lastCounterReset = now;
+                }
+
+                _status.TimeoutCount = _timeoutCount;
+                _status.ErrorCount = _errorCount;
+                _status.CompletedRequests = _completedRequests;
+                _status.ReadCount = _readCount;
+                _status.WriteCount = _writeCount;
+                _status.AverageResponseTime = (double)_totalResponseTime / (_readCount + _writeCount);
+                _status.TotalDataSize = _totalDataSize;
+                _status.DataThroughput = _status.TotalDataSize /
+                    (DateTime.Now - _status.StartTime.Value).TotalSeconds;
+            }
+        }
+        public void StopTest()
+        {
+            lock (_lockObject)
+            {
+                if (_status.IsRunning)
+                {
+                    _cancellationTokenSource?.Cancel();
+                    _status.IsRunning = false;
+                }
+            }
+        }
+
+        public TestStatus GetStatus()
+        {
+            return _status;
+        }
+    }
+    // TestStatus.cs 的修改部分
+    public class TestStatus
+    {
+        [JsonPropertyName("运行状态")]
+        public bool IsRunning { get; set; }
+
+        [JsonPropertyName("计划总请求数")]
+        public int TotalRequests { get; set; }
+
+        [JsonPropertyName("已完成请求数")]
+        public int CompletedRequests { get; set; }
+
+        [JsonPropertyName("超时次数")]
+        public int TimeoutCount { get; set; }
+
+        [JsonPropertyName("错误次数")]
+        public int ErrorCount { get; set; }
+
+        [JsonPropertyName("平均响应时间(ms)")]
+        public double AverageResponseTime { get; set; }
+
+        [JsonPropertyName("开始时间")]
+        public DateTime? StartTime { get; set; }
+
+        [JsonPropertyName("当前配置")]
+        public StressTestConfig CurrentConfig { get; set; }
+
+        [JsonPropertyName("进度百分比")]
+        public double ProgressPercentage => TotalRequests == 0 ? 0 : (CompletedRequests * 100.0 / TotalRequests);
+
+        [JsonPropertyName("读操作总数")]
+        public int ReadCount { get; set; }
+
+        [JsonPropertyName("写操作总数")]
+        public int WriteCount { get; set; }
+
+        [JsonPropertyName("读写比例")]
+        public double ReadWriteRatio => WriteCount == 0 ? 0 : (double)ReadCount / WriteCount;
+
+        [JsonPropertyName("每秒平均操作数")]
+        public double OperationsPerSecond => StartTime.HasValue
+            ? (ReadCount + WriteCount) / (DateTime.Now - StartTime.Value).TotalSeconds
+            : 0;
+
+        [JsonPropertyName("结束时间")]
+        public DateTime? EndTime { get; set; }
+
+        [JsonPropertyName("剩余时间(分钟)")]
+        public double RemainingMinutes => EndTime.HasValue ?
+            Math.Max(0, (EndTime.Value - DateTime.Now).TotalMinutes) : 0;
+
+        [JsonPropertyName("总数据量(字节)")]
+        public long TotalDataSize { get; set; }
+
+        [JsonPropertyName("数据吞吐量(字节/秒)")]
+        public double DataThroughput { get; set; }
+
+        [JsonPropertyName("数据吞吐量")]
+        public string FormattedThroughput
+        {
+            get
+            {
+                if (DataThroughput < 1024) return $"{DataThroughput:F2} B/s";
+                if (DataThroughput < 1024 * 1024) return $"{DataThroughput / 1024:F2} KB/s";
+                if (DataThroughput < 1024 * 1024 * 1024) return $"{DataThroughput / (1024 * 1024):F2} MB/s";
+                return $"{DataThroughput / (1024 * 1024 * 1024):F2} GB/s";
+            }
+        }
+
+        [JsonPropertyName("最近每秒操作数")]
+        public int LastSecondOperations { get; set; }
+
+        [JsonPropertyName("最近每秒读操作数")]
+        public int LastSecondReads { get; set; }
+
+        [JsonPropertyName("最近每秒写操作数")]
+        public int LastSecondWrites { get; set; }
+    }
+
+    // StressTestConfig.cs 的修改部分
+    public class StressTestConfig
+    {
+        [JsonPropertyName("并发任务数")]
+        public int ConcurrentTasks { get; set; } = 100;
+
+        [JsonPropertyName("超时时间(ms)")]
+        public int TimeoutMs { get; set; } = 1000;
+
+        [JsonPropertyName("读写比例")]
+        public int ReadsPerWrite { get; set; } = 10;
+
+        [JsonPropertyName("操作间隔(ms)")]
+        public int OperationIntervalMs { get; set; } = 0;
+
+        [JsonPropertyName("数据大小(KB)")]
+        public int ValueSizeKB { get; set; } = 10;
+    }
+
+}

+ 13 - 13
molilian.api/Controllers/public/TaskController.cs

@@ -31,7 +31,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetRawItemIdTask(int limit = 100)
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             string message = string.Empty;
             int total = 0;
@@ -91,7 +91,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetSettleBills(int sleep = 2000)
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
 
             string message = string.Empty;
@@ -126,7 +126,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetHistoryOrders(int id, int sleep, DateTime startTime, DateTime endTime)
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             if (id == 0) return new APIResult(new { success = false, message = "没有有效账号", });
 
@@ -165,7 +165,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetIncyOrders(int sleep = 2000)
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             string message = string.Empty;
             int total = 0;
@@ -201,7 +201,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetOrdersByAdZone(int id, long adzoneId, int sleep, DateTime startTime, DateTime endTime)
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             string message = string.Empty;
             int total = 0;
@@ -234,7 +234,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetHistoryRefundOrders(int id, int sleep, DateTime startTime, DateTime endTime)
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             if (id == 0) return new APIResult(new { success = false, message = "没有有效账号", });
 
@@ -273,7 +273,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetIncyRefundOrders(int sleep = 2000)
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             string message = string.Empty;
             int total = 0;
@@ -310,7 +310,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetViolationuWarning()
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             string message = string.Empty;
             foreach (var account in list)
@@ -486,7 +486,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> GetDrawBalance()
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             string message = string.Empty;
             foreach (var account in list)
@@ -518,7 +518,7 @@ namespace molilian.api.Controllers
             string message = string.Empty;
 
 
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list != null)
             {
                 foreach (var account in list)
@@ -701,7 +701,7 @@ namespace molilian.api.Controllers
         {
             string message = string.Empty;
 
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list != null)
             {
                 foreach (var account in list)
@@ -832,7 +832,7 @@ namespace molilian.api.Controllers
                 return new APIResult(new { success = false, message = "日期错误", });
             }
 
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             string message = string.Empty;
             foreach (var account in list)
@@ -941,7 +941,7 @@ namespace molilian.api.Controllers
             string message;
 
             //============================== 放弃转链-没有匹配账号 ==============================
-            TkPoolDTO? account = TkPoolCore.GetOne(accountid);
+            TkPoolDTO? account = await TkPoolCore.GetOneAsync(accountid);
             if (account == null)
             {
                 return new APIResult(new

+ 1 - 1
molilian.api/Controllers/public/TestController.cs

@@ -432,7 +432,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> xxx()
         {
-            var list = TkPoolCore.List();
+            var list = await TkPoolCore.ListAsync();
             if (list == null) return new APIResult(new { success = false, message = "没有有效账号", });
             string message = string.Empty;
             foreach (var account in list)

+ 8 - 11
molilian.api/Controllers/public/TkController.cs

@@ -63,7 +63,7 @@ namespace molilian.api.Controllers
                 return new APIResult(new { success = false, message = "验证错误2" }, APIResultCodeEnum.Unauthorized);
             }
 
-            var account = ApiAccountCore.GetOne(a);
+            var account = await ApiAccountCore.GetOneAsync(a);
             if (account == null)
             {
                 return new APIResult(new { success = false, message = "验证错误3" }, APIResultCodeEnum.Unauthorized);
@@ -113,7 +113,7 @@ namespace molilian.api.Controllers
 #endif
             for (int i = 0; i < count; i++)
             {
-                _ = UnionParseCore.UnionParseAsync(content[i], channel, commerceType, ip, oaid, accountid, clickId);
+                _ = await UnionParseCore.UnionParseAsync(content[i], channel, commerceType, ip, oaid, accountid, clickId);
             }
             return new APIResult(new { msg = "ok" });
         }
@@ -143,7 +143,7 @@ namespace molilian.api.Controllers
                 return new APIResult(new { success = false, message = "验证错误2" }, APIResultCodeEnum.Unauthorized);
             }
 
-            var account = ApiAccountCore.GetOne(a);
+            var account = await ApiAccountCore.GetOneAsync(a);
             if (account == null)
             {
                 return new APIResult(new { success = false, message = "验证错误3" }, APIResultCodeEnum.Unauthorized);
@@ -213,7 +213,7 @@ namespace molilian.api.Controllers
                     });
                 }
 
-                var account = TkPoolCore.GetOne(TkPoolCore.TkAction.parse);
+                var account = await TkPoolCore.GetOneAsync(TkPoolCore.TkAction.parse);
                 if (account == null)
                 {
                     result.success = false;
@@ -389,9 +389,7 @@ namespace molilian.api.Controllers
         [HttpGet]
         public async Task<ActionResult> dplist([FromQuery] string query = "", [FromQuery] string a = "", [FromQuery] int t = 0, [FromQuery] string sign = "")
         {
-#if DEBUG
 
-#else
             //验证签名
             if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(sign))
             {
@@ -404,7 +402,7 @@ namespace molilian.api.Controllers
                 return new APIResult(new { success = false, message = "验证错误2" }, APIResultCodeEnum.Unauthorized);
             }
 
-            var account = ApiAccountCore.GetOne(a);
+            var account = await ApiAccountCore.GetOneAsync(a);
             if (account == null)
             {
                 return new APIResult(new { success = false, message = "验证错误3" }, APIResultCodeEnum.Unauthorized);
@@ -419,9 +417,8 @@ namespace molilian.api.Controllers
             {
                 return new APIResult(new { success = false, message = "查询条件不能为空" });
             }
-#endif
             string filter = $"batchId=@query";
-            var account_list = TkPoolCore.List();
+            var account_list = await TkPoolCore.ListAsync();
             List<int> account_ids = [];
             if (account_list.Any())
             {
@@ -470,7 +467,7 @@ namespace molilian.api.Controllers
         public async Task<ActionResult> unsafeParseDpList([FromQuery] string query = "")
         {
             string filter = $"batchId=@query";
-            var account_list = TkPoolCore.List();
+            var account_list = await TkPoolCore.ListAsync();
             List<int> account_ids = [];
             if (account_list.Any())
             {
@@ -534,7 +531,7 @@ namespace molilian.api.Controllers
                 return new APIResult(new { success = false, message = "验证错误2" }, APIResultCodeEnum.Unauthorized);
             }
 
-            var account = ApiAccountCore.GetOne(a);
+            var account = await ApiAccountCore.GetOneAsync(a);
             if (account == null || !account.enable_report)
             {
                 _ = log.Info($"a:{a}\tt:{t}\tsign:{sign}\t", $"message:验证错误3")

+ 3 - 3
molilian.api/Dockerfile

@@ -35,9 +35,9 @@ WORKDIR /app
 COPY --from=publish /app/publish .
 
 # 设置区域设置和字符编码
-ENV LANG en_US.UTF-8
-ENV LANGUAGE en_US:en
-ENV LC_ALL en_US.UTF-8
+ENV LANG=en_US.UTF-8
+ENV LANGUAGE=en_US:en
+ENV LC_ALL=en_US.UTF-8
 
 # 设置时区
 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

+ 2 - 1
molilian.api/Properties/PublishProfiles/latest.pubxml

@@ -13,5 +13,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
     <ProjectGuid>5a0a088d-3cf8-4378-9139-68895e5c89df</ProjectGuid>
     <_TargetId>DockerCustomContainerRegistry</_TargetId>
     <PublishImageTag>latest</PublishImageTag>
-  </PropertyGroup>
+  
+</PropertyGroup>
 </Project>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
molilian.api/Properties/PublishProfiles/latest.pubxml.user


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
molilian.api/Properties/PublishProfiles/tester.pubxml.user


+ 2 - 1
molilian.api/molilian.api.csproj

@@ -6,6 +6,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <UserSecretsId>c3335e1a-a292-4152-b069-20530f5a6b83</UserSecretsId>
     <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
+    <ContainerImageTags>$(Version);latest</ContainerImageTags>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'" />
@@ -14,7 +15,7 @@
     <PackageReference Include="dodohold.core" Version="1.0.1.17" />
     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.0-Preview.1" />
     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
-    <PackageReference Include="YunhuiKit" Version="0.0.3" />
+    <PackageReference Include="YunhuiKit" Version="0.0.5" />
   </ItemGroup>
 
   <ItemGroup>

+ 9 - 7
molilian.core/Core/API/ApiAccountCore.cs

@@ -29,35 +29,37 @@ namespace molilian.core
     {
         private static readonly object _lockObj = new();
         private static IEnumerable<ApiAccountDTO> _cached;
-        public static ApiAccountDTO? GetOne(string api_key)
+        public static async Task<ApiAccountDTO> GetOneAsync(string api_key)
         {
-            var list = List();
+            var list = await ListAsync();
             if (!list.Any()) return null;
             return list.Where(e => e.api_key == api_key).FirstOrDefault();
         }
 
 
-        public static IEnumerable<ApiAccountDTO> List(bool force = false)
+        public static async Task<IEnumerable<ApiAccountDTO>> ListAsync(bool force = false)
         {
             if (!force && _cached != null) return _cached;
 
             string cache_key = $"cache:api_key";
-            var list = RedisHelper.Get<IEnumerable<ApiAccountDTO>>(cache_key);
+            var list = await RedisHelper.GetAsync<IEnumerable<ApiAccountDTO>>(cache_key);
             if (force || list == null)
             {
                 lock (_lockObj)
                 {
                     list = new DBContext.Table("api_account").Select<ApiAccountDTO>();
                     if (list == null) return default;
-                    RedisHelper.Set(cache_key, list, 30 * 86400);
+                    _ = RedisHelper.SetAsync(cache_key, list, 30 * 86400);
                 }
             }
             _cached = list;
             return list;
         }
+
+
         public static void Refresh()
         {
-            _ = List(true);
+            _ = ListAsync(true);
         }
 
         public static void Disabled(string name)
@@ -71,7 +73,7 @@ namespace molilian.core
                 .Add("status", 0)
                 .Where("name=@name", new { name })
                 .Update();
-            _ = List(true);
+            _ = ListAsync(true);
             EndPointCore.NotifyReload();
         }
 

+ 13 - 11
molilian.core/Core/EndPointCore.cs

@@ -119,22 +119,24 @@ Server=rm-2ze74506m3gfsqe7mco.rwlb.rds.aliyuncs.com; Port=3306; Database=coupon;
         {
             var resultList = new List<T>();
             var list = List(force);
-            foreach (var node in list)
-            {
-                var result = await nodeAction(node);
-                if (result != null) resultList.Add(result);
-            }
-            return resultList;
+
+            var tasks = list.Select(node => nodeAction(node));
+            var results = await Task.WhenAll(tasks);
+
+            return results.Where(result => result != null).ToList();
+
+            //foreach (var node in list)
+            //{
+            //    var result = await nodeAction(node);
+            //    if (result != null) resultList.Add(result);
+            //}
+            //return resultList;
         }
 
         public static async Task ProcessEndPointNodesAsync(Func<EndPointDTO, Task> nodeAction, bool force = false)
         {
             var list = List(force);
-            var tasks = new List<Task>();
-            foreach (var node in list)
-            {
-                tasks.Add(nodeAction(node));
-            }
+            var tasks = list.Select(node => nodeAction(node));
             await Task.WhenAll(tasks);
         }
 

+ 3 - 0
molilian.core/Core/aliyun/AliyunCore.cs

@@ -80,6 +80,9 @@ namespace molilian.core
                     sellCountStr = $"{item.Volume}",
                     provcity = item.Provcity
                 };
+
+                if (newItem.h5_url.StartsWith("//")) newItem.h5_url = "https:" + newItem.h5_url;
+                if (newItem.pic.StartsWith("//")) newItem.pic = "https:" + newItem.pic;
                 arr.Add(newItem);
             }
 

+ 4 - 4
molilian.core/Core/cps/CpsPoolCore.cs

@@ -148,8 +148,8 @@ namespace molilian.core
                         .Select<CpsLinksDTO>();
             foreach (var item in list)
             {
-                RiskControlCore.SetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                RiskControlCore.SetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                RiskControlCore.SetCallsAsync(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                RiskControlCore.SetCallsAsync(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
             }
             return list;
 
@@ -168,8 +168,8 @@ namespace molilian.core
                     if (list == null) return default;
                     foreach (var item in list)
                     {
-                        RiskControlCore.SetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                        RiskControlCore.SetCalls(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.cps, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
                     }
                     RedisHelper.Set(cache_key, list, 30 * 86400);
                 }

+ 2 - 2
molilian.core/Core/cps/ElePoolCore.cs

@@ -70,8 +70,8 @@ namespace molilian.core
 
                     foreach (var item in list)
                     {
-                        RiskControlCore.SetCalls(TkChannelEnum.eleme, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                        RiskControlCore.SetCalls(TkChannelEnum.eleme, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.eleme, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.eleme, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
                     }
                     RedisHelper.Set(cache_key, list, 30 * 86400);
                 }

+ 2 - 2
molilian.core/Core/cps/MeituanPoolCore.cs

@@ -66,8 +66,8 @@ namespace molilian.core
                     if (list == null) return default;
                     foreach (var item in list)
                     {
-                        RiskControlCore.SetCalls(TkChannelEnum.meituan, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                        RiskControlCore.SetCalls(TkChannelEnum.meituan, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.meituan, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.meituan, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
                     }
                     RedisHelper.Set(cache_key, list, 30 * 86400);
                 }

+ 2 - 1
molilian.core/Core/cps/UnionCpsCore.cs

@@ -18,6 +18,7 @@ using System.Security.Cryptography;
 using Google.Protobuf.WellKnownTypes;
 using System.Threading.Channels;
 using TencentCloud.Tione.V20211111.Models;
+using COSXML.Network;
 
 
 namespace molilian.core
@@ -262,7 +263,7 @@ namespace molilian.core
                     });
                 }
 
-                var account = TkPoolCore.GetOne(TkPoolCore.TkAction.parse);
+                var account = await TkPoolCore.GetOneAsync(TkPoolCore.TkAction.parse);
                 if (account == null)
                 {
                     result.success = false;

+ 2 - 2
molilian.core/Core/jd/JdPoolCore.cs

@@ -133,8 +133,8 @@ namespace molilian.core
 
                     foreach (var item in list)
                     {
-                        RiskControlCore.SetCalls(TkChannelEnum.jd, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                        RiskControlCore.SetCalls(TkChannelEnum.jd, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.jd, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.jd, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
                     }
                     RedisHelper.Set(cache_key, list, 30 * 86400);
                 }

+ 2 - 2
molilian.core/Core/ks/KsPoolCore.cs

@@ -103,8 +103,8 @@ namespace molilian.core
 
                     foreach (var item in list)
                     {
-                        RiskControlCore.SetCalls(TkChannelEnum.ks, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                        RiskControlCore.SetCalls(TkChannelEnum.ks, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.ks, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.ks, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
                     }
                     RedisHelper.Set(cache_key, list, 30 * 86400);
                 }

+ 61 - 0
molilian.core/Core/log/base.cs

@@ -21,6 +21,7 @@ using COSXML.Network;
 using System.Security.Policy;
 using System.Diagnostics;
 using TencentCloud.Ecm.V20190719.Models;
+using YunhuiKit;
 
 
 namespace molilian.core
@@ -657,6 +658,66 @@ namespace molilian.core
             return result.Sum();
         }
 
+        public static async Task<int> GetTotalAsync(string keyname, bool all_node = true)
+        {
+            async Task<int> ProcessNode(EndPointDTO node)
+            {
+                if (!IsValidNode(node, all_node)) return 0;
+
+                var redisServer = GetRedisServer(node);
+                if (string.IsNullOrEmpty(redisServer)) return 0;
+
+                try
+                {
+                    //var redis = RedisClientManager.GetRedisClient(redisServer);
+                    await using var scope = RedisClientFactory.CreateScope(redisServer);
+                    var client = scope.Client;
+                    return await client.GetAsync<int>(keyname);
+                }
+                catch (Exception ex)
+                {
+                    // 可以添加日志记录
+                    return 0;
+                }
+            }
+
+            var result = await EndPointCore.ProcessEndPointNodesTaskAsync<int>(ProcessNode);
+            return result.Sum();
+        }
+
+        private static bool IsValidNode(EndPointDTO node, bool all_node)
+        {
+            if (!node.is_public_api || string.IsNullOrEmpty(node.redis_server))
+                return false;
+
+            if (!all_node)
+            {
+                if (CenterHub.IsCenter)
+                    return !node.is_coupon_api;
+                else
+                    return node.is_coupon_api;
+            }
+
+            return true;
+        }
+
+        private static string GetRedisServer(EndPointDTO node)
+        {
+#if DEBUG
+            return node.name switch
+            {
+                "bj" => "101.200.46.46:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook",
+                "gz" => "8.138.110.158:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook",
+                "coupon1" => "123.56.185.166:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=coupon",
+                _ => string.Empty
+            };
+#else
+    return node.redis_server;
+#endif
+        }
+
+
+
         public static string[] GetTotalKeys(string keyname, bool all_node = true)
         {
 

+ 2 - 2
molilian.core/Core/log/coupon.cs

@@ -21,7 +21,7 @@ namespace molilian.core
                     if (data == null) break;
 
                     if (_test_oaid.Equals(data.oaid) ||
-                         data.ip.Contains("127.0.0"))
+                         data.ip.StartsWith("127.0.0"))
                     {
                         var test_data = data.Convert2Json().Convert2Object<TestUnionCouponDTO>();
                         connection.Insert(test_data);
@@ -62,7 +62,7 @@ namespace molilian.core
                 response.elapsedTime = (int)ts.TotalMilliseconds;
                 _ = RedisHelper.RPushAsync(queue_coupon_key, response);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveCouponCache(response.channel.ToString(), response.accountId, response.accountName, response.success, response.message, response.reason);
                 }

+ 2 - 2
molilian.core/Core/log/cps.cs

@@ -23,7 +23,7 @@ namespace molilian.core
                     if (data == null) break;
 
                     if (_test_oaid.Equals(data.oaid) ||
-                         data.ip.Contains("127.0.0"))
+                         data.ip.StartsWith("127.0.0"))
                     {
                         var test_data = data.Convert2Json().Convert2Object<TestUnionCpsDTO>();
                         connection.Insert(test_data);
@@ -95,7 +95,7 @@ namespace molilian.core
                     saveClientRequestTotal(response.channel, response.ip, response.oaid);
                 }
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveCpsCache(response.channel, response.accountId,
                         response.success, response.message, response.reason);

+ 2 - 2
molilian.core/Core/log/deeplink.cs

@@ -27,7 +27,7 @@ namespace molilian.core
 
 
                     if (_test_oaid.Equals(data.oaid) ||
-                         data.ip.Contains("127.0.0"))
+                         data.ip.StartsWith("127.0.0"))
                     {
                         save_dp_parse_logs(data, "deeplink_parse_logs_test", connection, transaction);
                     }
@@ -111,7 +111,7 @@ namespace molilian.core
                 response.elapsedTime = (int)ts.TotalMilliseconds;
                 _ = RedisHelper.RPushAsync(queue_deeplink_parse_key, response);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveParseCache(response.channel_name, 0, "tool",
                         response.success, response.message, response.reason,

+ 1 - 1
molilian.core/Core/log/dy.cs

@@ -79,7 +79,7 @@ namespace molilian.core
 
                 if (response.success) saveClientRequestTotal(response.channel, response.ip, response.oaid);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveParseCache(response.channel.ToString(), response.accountId,
                         response.accountName, response.success, response.message, response.reason,

+ 2 - 2
molilian.core/Core/log/jd.cs

@@ -23,7 +23,7 @@ namespace molilian.core
 
 
                     if (_test_oaid.Equals(data.oaid) ||
-                         data.ip.Contains("127.0.0"))
+                         data.ip.StartsWith("127.0.0"))
                     {
                         save_jd_parse_logs(data, "jd_parse_logs_test", connection, transaction);
                     }
@@ -73,7 +73,7 @@ namespace molilian.core
                 response.elapsedTime = (int)ts.TotalMilliseconds;
                 _ = RedisHelper.RPushAsync(queue_parse_jd_key, response);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveParseCache(response.channel.ToString(), response.accountId,
                         response.accountName, response.success, response.message, response.reason,

+ 2 - 2
molilian.core/Core/log/ks.cs

@@ -22,7 +22,7 @@ namespace molilian.core
                     if (data == null) break;
 
 
-                    if (_test_oaid.Equals(data.oaid) || data.ip.Contains("127.0.0"))
+                    if (_test_oaid.Equals(data.oaid) || data.ip.StartsWith("127.0.0"))
                     {
                         save_ks_parse_logs(data, "ks_parse_logs_test", connection, transaction);
                     }
@@ -68,7 +68,7 @@ namespace molilian.core
                 response.elapsedTime = (int)ts.TotalMilliseconds;
                 _ = RedisHelper.RPushAsync(queue_parse_ks_key, response);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveParseCache(response.channel.ToString(), response.accountId,
                         response.accountName, response.success, response.message, response.reason,

+ 2 - 2
molilian.core/Core/log/pdd.cs

@@ -23,7 +23,7 @@ namespace molilian.core
 
 
                     if (_test_oaid.Equals(data.oaid) ||
-                         data.ip.Contains("127.0.0"))
+                         data.ip.StartsWith("127.0.0"))
                     {
                         save_pdd_parse_logs(data, "pdd_parse_logs_test", connection, transaction);
                     }
@@ -68,7 +68,7 @@ namespace molilian.core
                 response.elapsedTime = (int)ts.TotalMilliseconds;
                 _ = RedisHelper.RPushAsync(queue_parse_pdd_key, response);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveParseCache(response.channel.ToString(), response.accountId,
                         response.accountName, response.success, response.message, response.reason,

+ 2 - 2
molilian.core/Core/log/taobao.cs

@@ -23,7 +23,7 @@ namespace molilian.core
                     if (data == null) break;
 
                     if (_test_oaid.Equals(data.oaid) ||
-                         data.ip.Contains("127.0.0"))
+                         data.ip.StartsWith("127.0.0"))
                     {
                         save_tk_parse_logs(data, "tk_parse_logs_test", connection, transaction);
                     }
@@ -101,7 +101,7 @@ namespace molilian.core
                 {
                     _ = saveUnionCouponParseCacheAsync(response);
                 }
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveParseCache(response.channel.ToString(), response.accountId,
                         response.accountName, response.success, response.message, response.reason,

+ 2 - 2
molilian.core/Core/log/tool.cs

@@ -24,7 +24,7 @@ namespace molilian.core
 
 
                     if (_test_oaid.Equals(data.oaid) ||
-                         data.ip.Contains("127.0.0"))
+                         data.ip.StartsWith("127.0.0"))
                     {
                         new DBContext.Table(connection, "tool_parse_logs_test")
                             .Add("end_point", data.end_point)
@@ -90,7 +90,7 @@ namespace molilian.core
                 response.elapsedTime = (int)ts.TotalMilliseconds;
                 _ = RedisHelper.RPushAsync(queue_parse_tool_key, response);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveParseCache(response.channel.ToString(), 0, "tool",
                         response.success, response.message, response.reason,

+ 3 - 3
molilian.core/Core/log/第三方旧接口.cs

@@ -24,7 +24,7 @@ namespace molilian.core
                     if (data == null) break;
 
                     if (_test_oaid.Equals(data.oaid) ||
-                         data.ip.Contains("127.0.0"))
+                         data.ip.StartsWith("127.0.0"))
                     {
                         save_tk_log(data, "tk_logs_test", connection, transaction);
                     }
@@ -91,7 +91,7 @@ namespace molilian.core
                 response.elapsedTime = (int)ts.TotalMilliseconds;
                 _ = RedisHelper.RPushAsync(queue_jd_key, response);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveCache(response.channel.ToString(), response.accountId, response.accountName, response.success, response.message, response.reason);
                 }
@@ -106,7 +106,7 @@ namespace molilian.core
                 response.elapsedTime = (int)ts.TotalMilliseconds;
                 _ = RedisHelper.RPushAsync(queue_tb_key, response);
 
-                if (!response.ip.Contains("127.0.0"))
+                if (!response.ip.StartsWith("127.0.0"))
                 {
                     saveCache(response.channel.ToString(), response.accountId, response.accountName, response.success, response.message, response.reason);
                 }

+ 2 - 2
molilian.core/Core/pdd/PddPoolCore.cs

@@ -93,8 +93,8 @@ namespace molilian.core
                     if (list == null) return default;
                     foreach (var item in list)
                     {
-                        RiskControlCore.SetCalls(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                        RiskControlCore.SetCalls(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                        RiskControlCore.SetCallsAsync(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
                     }
                     RedisHelper.Set(cache_key, list, 30 * 86400);
                 }

+ 3 - 3
molilian.core/Core/taoke/RiskControlCore.cs

@@ -47,7 +47,7 @@ namespace molilian.core
             RedisHelper.Expire(cache_key, 3 * 86400);
         }
 
-        internal static void SetCalls(TkChannelEnum channel, int accountId, string flag, int val)
+        internal static async Task SetCallsAsync(TkChannelEnum channel, int accountId, string flag, int val)
         {
             string key = $"{channel}:{accountId}:{flag}";
             if (_calls.ContainsKey(key))
@@ -59,8 +59,8 @@ namespace molilian.core
                 _calls[key] = val;
             }
             string cache_key = $"RiskControl:{key}:calls:{flag}";
-            RedisHelper.IncrBy(cache_key);
-            RedisHelper.Expire(cache_key, 3 * 86400);
+            RedisHelper.IncrByAsync(cache_key);
+            RedisHelper.ExpireAsync(cache_key, 3 * 86400);
         }
 
         public static int GetAllNodesCalls(TkChannelEnum channel, int accountId, string flag)

+ 19 - 19
molilian.core/Core/taoke/TaokeOpenCore.cs

@@ -73,11 +73,11 @@ namespace molilian.core
                 TkPoolDTO account;
                 if (aid == 0)
                 {
-                    account = TkPoolCore.GetOne(TkPoolCore.TkAction.promotionQuery);
+                    account = await TkPoolCore.GetOneAsync(TkPoolCore.TkAction.promotionQuery);
                 }
                 else
                 {
-                    account = TkPoolCore.GetOne(aid);
+                    account = await TkPoolCore.GetOneAsync(aid);
                 }
                 if (account == null)
                 {
@@ -130,23 +130,23 @@ namespace molilian.core
                             result.proxy_node = null;
 
                             var api = VeapiPoolCore.Get(account.api_id);
-                                var core = new VeapiPlus(account.name, api.key, api.sessionKey);
-                                core.picSimilaritem(img, ref result);
-
-                                var ts2 = DateTime.Now - stime;
-                                result.elapsedTime2 = (int)ts2.TotalMilliseconds;
-
-                                _ = TkLogCore.PromotionImgLogAsync(result);
-                                return new APIResult(new
-                                {
-                                    result.success,
-                                    result.message,
-                                    result.reason,
-                                    promotionImg = result.PromotionImg
-                                }, APIResultCodeEnum.OK, new JsonSerializerOptions
-                                {
-                                    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
-                                });
+                            var core = new VeapiPlus(account.name, api.key, api.sessionKey);
+                            core.picSimilaritem(img, ref result);
+
+                            var ts2 = DateTime.Now - stime;
+                            result.elapsedTime2 = (int)ts2.TotalMilliseconds;
+
+                            _ = TkLogCore.PromotionImgLogAsync(result);
+                            return new APIResult(new
+                            {
+                                result.success,
+                                result.message,
+                                result.reason,
+                                promotionImg = result.PromotionImg
+                            }, APIResultCodeEnum.OK, new JsonSerializerOptions
+                            {
+                                Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
+                            });
                         }
                         break;
                     case "aliyun":

+ 58 - 32
molilian.core/Core/taoke/TkPoolCore.cs

@@ -30,17 +30,18 @@ namespace molilian.core
             _end_point = Environment.GetEnvironmentVariable("EndPoint");
         }
 
-        private static readonly object _lockObj = new();
+        private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
+
         private static IEnumerable<TkPoolDTO> _cached;
-        public static TkPoolDTO? GetOne(TkAction action)
+        public static async Task<TkPoolDTO> GetOneAsync(TkAction action)
         {
-            var list = List();
+            var list = await ListAsync();
             if (!list.Any()) return null;
             return list.Where(e => FilterNodes(e, action)).OrderBy(l => Guid.NewGuid()).FirstOrDefault();
         }
-        public static TkPoolDTO? GetOne(int id)
+        public static async Task<TkPoolDTO> GetOneAsync(int id)
         {
-            var list = List();
+            var list = await ListAsync();
             if (!list.Any()) return null;
             return list.Where(e => e.id == id).FirstOrDefault();
         }
@@ -84,42 +85,67 @@ namespace molilian.core
             if (item.daily_income_limit == 0) return true;
             decimal income_amt = RiskControlCore.GetIncomeAmt(TkChannelEnum.tb, $"{item.id}");
             return income_amt < item.daily_income_limit;
-        } 
-
+        }
 
-        public static IEnumerable<TkPoolDTO> List(bool force = false)
+        public static async Task<IEnumerable<TkPoolDTO>> ListAsync(bool force = false)
         {
-
+            // 内存缓存检查
             if (!force && _cached != null) return _cached;
+            string cache_key = "cache:tk_pool";
 
-            string cache_key = $"cache:tk_pool";
-            var list = RedisHelper.Get<IEnumerable<TkPoolDTO>>(cache_key);
-            if (force || list == null)
+            if (!force)
             {
-                lock (_lockObj)
+                var cachedList = await RedisHelper.GetAsync<IEnumerable<TkPoolDTO>>(cache_key);
+                if (cachedList != null)
                 {
-                    list = new DBContext.Table("tk_pool")
-                        .Where("status=@status", new { status = 1 })
-                        .Select<TkPoolDTO>();
-
-                    list = new DBContext.Table("tk_pool")
-                        .Where("status=@status", new { status = 1 })
-                        .Select<TkPoolDTO>();
-                    if (list == null) return default;
-                    foreach (var item in list)
+                    _cached = cachedList;
+                    return cachedList;
+                }
+            }
+            // 获取新数据
+            await _semaphore.WaitAsync();
+            try
+            {
+                // 双重检查,防止并发情况下重复加载
+                if (!force)
+                {
+                    var cachedList = await RedisHelper.GetAsync<IEnumerable<TkPoolDTO>>(cache_key);
+                    if (cachedList != null)
                     {
-                        RiskControlCore.SetCalls(TkChannelEnum.tb, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                        RiskControlCore.SetCalls(TkChannelEnum.tb, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                        _cached = cachedList;
+                        return cachedList;
                     }
-                    RedisHelper.Set(cache_key, list, 30 * 86400);
                 }
+
+                // 从数据库加载数据
+                var list = new DBContext.Table("tk_pool")
+                    .Where("status=@status", new { status = 1 })
+                    .Select<TkPoolDTO>();
+
+                if (list == null) return default;
+
+                // 更新调用次数
+                foreach (var item in list)
+                {
+                    _ = RiskControlCore.SetCallsAsync(TkChannelEnum.tb, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                    _ = RiskControlCore.SetCallsAsync(TkChannelEnum.tb, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                }
+
+                // 更新缓存
+                await RedisHelper.SetAsync(cache_key, list, 30 * 86400);
+                _cached = list;
+                return list;
+            }
+            finally
+            {
+                _semaphore.Release();
             }
-            _cached = list;
-            return list;
         }
+
+
         public static void Refresh()
         {
-            _ = List(true);
+            _ = ListAsync(true);
         }
         public static void UpdateDrawBalance(string name, decimal amout)
         {
@@ -127,7 +153,7 @@ namespace molilian.core
                 .Add("draw_balance", amout)
                 .Where("name=@name", new { name })
                 .Update();
-            _ = List(true);
+            _ = ListAsync(true);
         }
 
         public static void Suspend(string endpoint, int accountId, string name, string content)
@@ -147,7 +173,7 @@ namespace molilian.core
             {
                 update.Where("name=@name", new { name }).Update();
             }
-            _ = List(true);
+            _ = ListAsync(true);
             NotifyCore.Notify(new NifyMessage
             {
                 message = $"【淘客{accountId}:{name}】{endpoint} 暂停",
@@ -178,7 +204,7 @@ namespace molilian.core
                 update.Where("name=@name", new { name }).Update();
             }
 
-            _ = List(true);
+            _ = ListAsync(true);
 
             NotifyCore.Notify(new NifyMessage
             {
@@ -219,7 +245,7 @@ namespace molilian.core
                    .Add("login_time", DateTime.Now)
                    .Where("id=@id", new { exist.id })
                    .Update();
-                if (status == 1) _ = List(true);
+                if (status == 1) _ = ListAsync(true);
             }
             else
             {

+ 1 - 1
molilian.core/Core/taoke/UnionCouponCore.cs

@@ -104,7 +104,7 @@ namespace molilian.core
                     });
                 }
 
-                var account = TkPoolCore.GetOne(TkPoolCore.TkAction.coupon);
+                var account = await TkPoolCore.GetOneAsync(TkPoolCore.TkAction.coupon);
                 if (account == null)
                 {
                     result.success = false;

+ 26 - 26
molilian.core/Core/taoke/UnionParseCore.cs

@@ -247,18 +247,18 @@ namespace molilian.core
 
 
                     //20241229 特例
-                    if ("bj".Equals(EndPointCore.CurrentEndPoint))
-                    {
-                        string ruleKey = $"tmp_rules2:tb:{DateTime.Now:yyyyMMdd}";
-                        var count = RedisHelper.Get<int>(ruleKey);
-                        var now = DateTime.Now;
-                        if (now > new DateTime(2024, 12, 19) && now <= new DateTime(2024, 12, 22) && now.Hour >= 7 && count < 1000)
-                        {
-                            result.deeplink_url = "tbopen://m.taobao.com/tbopen/index.html?source=auto&action=ali.open.nav&module=h5&bootImage=0&afc_route=1&bc_fl_src=growth_dhh_2200803434968_100-1930985-1595034112&dpa_Inid=159503411212096&dpa_material_id=530637422585&dpa_material_type=1&dpa_source_code=12096&force_no_smb=true&h5Url=https%3A%2F%2Fs.m.taobao.com%2Fh5%3Ffrom%3Dcustoms%26g_channelSrp%3Ddhhdpa_1232552832%26dpa_material_type%3D1%26ut_sk%3Dsearch%26spm%3Da2141.mb819t211c7%26sLaunch%3D0%26sKeep%3D1%26sModuleName%3Dsearch%26spm_back_up%3Da2141.mb819t211c7%26bc_fl_src%3Dgrowth_dhh_2200803434968_100-1930985-1595034112%26dpa_Inid%3D159503411212096%26dpa_material_id%3D530637422585%26dpa_material_type%3D1%26dpa_source_code%3D12096%26force_no_smb%3Dtrue%26itemIds%3D530637422585%26slk_actid%3D100000000207%26spm%3D2014.ugdhh.2200803434968.100-1930985-1595034112%26wh_biz%3Dtm&itemIds=530637422585&slk_actid=100000000207&spm=2014.ugdhh.2200803434968.100-1930985-1595034112&wh_biz=tm";
-                            RedisHelper.IncrBy(ruleKey);
-                            RedisHelper.Expire(ruleKey, 86400 * 1);
-                        }
-                    }
+                    //if ("bj".Equals(EndPointCore.CurrentEndPoint))
+                    //{
+                    //    string ruleKey = $"tmp_rules2:tb:{DateTime.Now:yyyyMMdd}";
+                    //    var count = RedisHelper.Get<int>(ruleKey);
+                    //    var now = DateTime.Now;
+                    //    if (now > new DateTime(2024, 12, 19) && now <= new DateTime(2024, 12, 22) && now.Hour >= 7 && count < 1000)
+                    //    {
+                    //        result.deeplink_url = "tbopen://m.taobao.com/tbopen/index.html?source=auto&action=ali.open.nav&module=h5&bootImage=0&afc_route=1&bc_fl_src=growth_dhh_2200803434968_100-1930985-1595034112&dpa_Inid=159503411212096&dpa_material_id=530637422585&dpa_material_type=1&dpa_source_code=12096&force_no_smb=true&h5Url=https%3A%2F%2Fs.m.taobao.com%2Fh5%3Ffrom%3Dcustoms%26g_channelSrp%3Ddhhdpa_1232552832%26dpa_material_type%3D1%26ut_sk%3Dsearch%26spm%3Da2141.mb819t211c7%26sLaunch%3D0%26sKeep%3D1%26sModuleName%3Dsearch%26spm_back_up%3Da2141.mb819t211c7%26bc_fl_src%3Dgrowth_dhh_2200803434968_100-1930985-1595034112%26dpa_Inid%3D159503411212096%26dpa_material_id%3D530637422585%26dpa_material_type%3D1%26dpa_source_code%3D12096%26force_no_smb%3Dtrue%26itemIds%3D530637422585%26slk_actid%3D100000000207%26spm%3D2014.ugdhh.2200803434968.100-1930985-1595034112%26wh_biz%3Dtm&itemIds=530637422585&slk_actid=100000000207&spm=2014.ugdhh.2200803434968.100-1930985-1595034112&wh_biz=tm";
+                    //        RedisHelper.IncrBy(ruleKey);
+                    //        RedisHelper.Expire(ruleKey, 86400 * 1);
+                    //    }
+                    //}
 
                     other_aff = true;
                     return TaobaoParseOutput(result, swData, new
@@ -284,18 +284,18 @@ namespace molilian.core
                     _ = TkLogCore.ParseLogAsync(result);
 
                     //20241229 特例
-                    if ("bj".Equals(EndPointCore.CurrentEndPoint))
-                    {
-                        string ruleKey = $"tmp_rules2:tb:{DateTime.Now:yyyyMMdd}";
-                        var count = RedisHelper.Get<int>(ruleKey);
-                        var now = DateTime.Now;
-                        if (now > new DateTime(2024, 12, 19) && now <= new DateTime(2024, 12, 22) && now.Hour >= 7 && count < 1000)
-                        {
-                            result.deeplink_url = "tbopen://m.taobao.com/tbopen/index.html?source=auto&action=ali.open.nav&module=h5&bootImage=0&afc_route=1&bc_fl_src=growth_dhh_2200803434968_100-1930985-1595034112&dpa_Inid=159503411212096&dpa_material_id=530637422585&dpa_material_type=1&dpa_source_code=12096&force_no_smb=true&h5Url=https%3A%2F%2Fs.m.taobao.com%2Fh5%3Ffrom%3Dcustoms%26g_channelSrp%3Ddhhdpa_1232552832%26dpa_material_type%3D1%26ut_sk%3Dsearch%26spm%3Da2141.mb819t211c7%26sLaunch%3D0%26sKeep%3D1%26sModuleName%3Dsearch%26spm_back_up%3Da2141.mb819t211c7%26bc_fl_src%3Dgrowth_dhh_2200803434968_100-1930985-1595034112%26dpa_Inid%3D159503411212096%26dpa_material_id%3D530637422585%26dpa_material_type%3D1%26dpa_source_code%3D12096%26force_no_smb%3Dtrue%26itemIds%3D530637422585%26slk_actid%3D100000000207%26spm%3D2014.ugdhh.2200803434968.100-1930985-1595034112%26wh_biz%3Dtm&itemIds=530637422585&slk_actid=100000000207&spm=2014.ugdhh.2200803434968.100-1930985-1595034112&wh_biz=tm";
-                            RedisHelper.IncrBy(ruleKey);
-                            RedisHelper.Expire(ruleKey, 86400 * 1);
-                        }
-                    }
+                    //if ("bj".Equals(EndPointCore.CurrentEndPoint))
+                    //{
+                    //    string ruleKey = $"tmp_rules2:tb:{DateTime.Now:yyyyMMdd}";
+                    //    var count = RedisHelper.Get<int>(ruleKey);
+                    //    var now = DateTime.Now;
+                    //    if (now > new DateTime(2024, 12, 19) && now <= new DateTime(2024, 12, 22) && now.Hour >= 7 && count < 1000)
+                    //    {
+                    //        result.deeplink_url = "tbopen://m.taobao.com/tbopen/index.html?source=auto&action=ali.open.nav&module=h5&bootImage=0&afc_route=1&bc_fl_src=growth_dhh_2200803434968_100-1930985-1595034112&dpa_Inid=159503411212096&dpa_material_id=530637422585&dpa_material_type=1&dpa_source_code=12096&force_no_smb=true&h5Url=https%3A%2F%2Fs.m.taobao.com%2Fh5%3Ffrom%3Dcustoms%26g_channelSrp%3Ddhhdpa_1232552832%26dpa_material_type%3D1%26ut_sk%3Dsearch%26spm%3Da2141.mb819t211c7%26sLaunch%3D0%26sKeep%3D1%26sModuleName%3Dsearch%26spm_back_up%3Da2141.mb819t211c7%26bc_fl_src%3Dgrowth_dhh_2200803434968_100-1930985-1595034112%26dpa_Inid%3D159503411212096%26dpa_material_id%3D530637422585%26dpa_material_type%3D1%26dpa_source_code%3D12096%26force_no_smb%3Dtrue%26itemIds%3D530637422585%26slk_actid%3D100000000207%26spm%3D2014.ugdhh.2200803434968.100-1930985-1595034112%26wh_biz%3Dtm&itemIds=530637422585&slk_actid=100000000207&spm=2014.ugdhh.2200803434968.100-1930985-1595034112&wh_biz=tm";
+                    //        RedisHelper.IncrBy(ruleKey);
+                    //        RedisHelper.Expire(ruleKey, 86400 * 1);
+                    //    }
+                    //}
 
                     other_aff = true;
                     return TaobaoParseOutput(result, swData, new
@@ -361,8 +361,8 @@ namespace molilian.core
 
                 //============================== 放弃转链-没有匹配账号 ==============================
                 TkPoolDTO? account = accountid > 0 ?
-                    TkPoolCore.GetOne(accountid) :
-                    TkPoolCore.GetOne(TkPoolCore.TkAction.parse);
+                    await TkPoolCore.GetOneAsync(accountid) :
+                    await TkPoolCore.GetOneAsync(TkPoolCore.TkAction.parse);
                 if (account == null)
                 {
                     result.success = false;

+ 1 - 1
molilian.core/Plus/Alimama/account.cs

@@ -187,7 +187,7 @@ namespace molilian.core
                     .Add("last_time", DateTime.Now)
                     .Where("name=@name", new { name = _accountName })
                     .Update();
-                _ = TkPoolCore.List(true);
+                _ = TkPoolCore.ListAsync(true);
 
                 NotifyCore.Notify(new NifyMessage
                 {

+ 4 - 4
molilian.core/Plus/Alimama/crawler.cs

@@ -15,7 +15,7 @@ namespace molilian.core
         /// 更新API调用日志(1天一次)
         /// </summary>
         /// <param name="intervalDay"></param>
-        public static void DailyLogs_bak(int intervalDay, string prefix = "", string channel = "all")
+        public static async void DailyLogs_bak(int intervalDay, string prefix = "", string channel = "all")
         {
             int channelId = (int)TkChannelEnum.tb;
             var db_prefix = channel switch
@@ -27,7 +27,7 @@ namespace molilian.core
 
             DateTime log_date = DateTime.Now.AddDays(-intervalDay).Date;
 
-            var accounts = TkPoolCore.List();
+            var accounts = await TkPoolCore.ListAsync();
             using var conn = DBContext.GetOpenConnection();
 
             foreach (var account in accounts)
@@ -133,7 +133,7 @@ namespace molilian.core
             DailyLogs(false, intervalDay, prefix, channel);
         }
 
-        public static void DailyLogs(bool all_node, int intervalDay, string prefix = "", string channel = "all")
+        public static async void DailyLogs(bool all_node, int intervalDay, string prefix = "", string channel = "all")
         {
             int channelId = (int)TkChannelEnum.tb;
             var db_prefix = channel switch
@@ -148,7 +148,7 @@ namespace molilian.core
 
             DateTime log_date = DateTime.Now.AddDays(-intervalDay).Date;
 
-            var accounts = TkPoolCore.List();
+            var accounts = await TkPoolCore.ListAsync();
             using var conn = all_node ? CenterHub.GetOpenConnection() : DBContext.GetOpenConnection();
             string tableName = all_node ? "center_daily_logs" : "daily_logs";
             string tableName2 = all_node ? "center_daily_chat_data" : "daily_chat_data";

+ 15 - 15
molilian.core/Plus/Alimama/parse.cs

@@ -121,18 +121,18 @@ namespace molilian.core
                 //result.deeplink_url = GetDeeplink(null);
                 //result.itemName = GetTitle(content);
 
-                if (!content.Contains("助我领红包") && !content.Contains("双11超级红包主会场"))
-                {
-                    //20241108 特例
-                    string ruleKey = $"tmp_rules:{DateTime.Now:yyyyMMdd}_2";
-                    var count = RedisHelper.IncrBy(ruleKey);
-                    if (DateTime.Now < DateTime.Parse("2024-11-11") && count < 1000)
-                    {
-                        string hb_url = "https://s.click.taobao.com/t?union_lens=lensId%3APUB%401730991020%400bbb0a39_0e75_193071ad936_c566%4001%40eyJmbG9vcklkIjozODg1Miiwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfYWN0aXZpdHlfb2ZmaWNpYWxfaW5kZXhfaHRtIn0ie%3BeventPageId%3A20150318020007201&e=m%3D2%26s%3DipuVKjYImbNw4vFB6t2Z2iperVdZeJviU%2F9%2F0taeK29yINtkUhsv0KWvzu%2FHMi3%2BFPhC4MirEWStw6LBB4w3HYXT%2BqQ2P5OIQVNSryTmvs7YddWYbxmvGTMNfihJN%2FGnAGIx0oe2X2hZfJ7ZQxC1%2FU3rpAhWgptfEBnEBk3xaGylLmcSHKfaX1CIFRJhZoJ2keMqUwSQcLRC0TzsMy8kp7Hfv3%2BBYcPW3eHn14rW1PB5SunYCHQHRbw6LwQYf%2F1JuyhJem%2BM5OoR2cbDLktPLiIOenYkFIXa2HzNl%2Bm1VXoil%2F2L3b1aA6a%2FoVHlY%2BqZ2kyLuBX5NHCAQVYCmAmuozC39JfnbJNrE%2FSR3F9BSjOYe76q6w0hyfybhwAASyyp5XMWEyz25ulHMwkL2n%2F7nNBiFmadXyjFDPu12TgSnbZtfjDbrVTLHb6MowVEq7z9LgOFRSuRLesvlLykGd2CaRk8ezhE61zXa8yR1eex6ip3KqbOh7CEmgCLaFxcnT%2BrGuviRFaBil8Mlu5kMKse3g%3D%3D";
-                        result.deeplink_url = GetDeeplink(hb_url);
-                        RedisHelper.Expire(ruleKey, 86400 * 10);
-                    }
-                }
+                //if (!content.Contains("助我领红包") && !content.Contains("双11超级红包主会场"))
+                //{
+                //    //20241108 特例
+                //    string ruleKey = $"tmp_rules:{DateTime.Now:yyyyMMdd}_2";
+                //    var count = RedisHelper.IncrBy(ruleKey);
+                //    if (DateTime.Now < DateTime.Parse("2024-11-11") && count < 1000)
+                //    {
+                //        string hb_url = "https://s.click.taobao.com/t?union_lens=lensId%3APUB%401730991020%400bbb0a39_0e75_193071ad936_c566%4001%40eyJmbG9vcklkIjozODg1Miiwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfYWN0aXZpdHlfb2ZmaWNpYWxfaW5kZXhfaHRtIn0ie%3BeventPageId%3A20150318020007201&e=m%3D2%26s%3DipuVKjYImbNw4vFB6t2Z2iperVdZeJviU%2F9%2F0taeK29yINtkUhsv0KWvzu%2FHMi3%2BFPhC4MirEWStw6LBB4w3HYXT%2BqQ2P5OIQVNSryTmvs7YddWYbxmvGTMNfihJN%2FGnAGIx0oe2X2hZfJ7ZQxC1%2FU3rpAhWgptfEBnEBk3xaGylLmcSHKfaX1CIFRJhZoJ2keMqUwSQcLRC0TzsMy8kp7Hfv3%2BBYcPW3eHn14rW1PB5SunYCHQHRbw6LwQYf%2F1JuyhJem%2BM5OoR2cbDLktPLiIOenYkFIXa2HzNl%2Bm1VXoil%2F2L3b1aA6a%2FoVHlY%2BqZ2kyLuBX5NHCAQVYCmAmuozC39JfnbJNrE%2FSR3F9BSjOYe76q6w0hyfybhwAASyyp5XMWEyz25ulHMwkL2n%2F7nNBiFmadXyjFDPu12TgSnbZtfjDbrVTLHb6MowVEq7z9LgOFRSuRLesvlLykGd2CaRk8ezhE61zXa8yR1eex6ip3KqbOh7CEmgCLaFxcnT%2BrGuviRFaBil8Mlu5kMKse3g%3D%3D";
+                //        result.deeplink_url = GetDeeplink(hb_url);
+                //        RedisHelper.Expire(ruleKey, 86400 * 10);
+                //    }
+                //}
                 return result;
             }
 
@@ -246,7 +246,7 @@ namespace molilian.core
             string result = string.Empty;
             if (matches.Count > 0)
             {
-                 result = Regex.Replace(matches[^1].Value, @"\++$", "");
+                result = Regex.Replace(matches[^1].Value, @"\++$", "");
             }
             result = result.Replace("&nbsp;", "");
 
@@ -501,7 +501,7 @@ namespace molilian.core
                 }
 
                 int limit_num = config.tk_limit_per_ip_24h;
-                if (!"127.0.0.1".Equals(ip) && limit_num > 0)
+                if (!ip.StartsWith("127.0.0") && limit_num > 0)
                 {
                     int num = TkLogCore.getClientRequestTotalByIp(TkChannelEnum.tb, ip);
                     if (num >= limit_num)
@@ -511,7 +511,7 @@ namespace molilian.core
                     }
                 }
                 limit_num = config.tk_limit_per_oaid_24h;
-                if (limit_num > 0)
+                if (!ip.StartsWith("127.0.0") && limit_num > 0)
                 {
                     int num = TkLogCore.getClientRequestTotalByOAID(TkChannelEnum.tb, oaid);
                     if (num >= limit_num)

+ 3 - 0
molilian.core/Plus/Aliyun/ImageSearch.cs

@@ -27,6 +27,7 @@ namespace molilian.core
                 {
                     AccessKeyId = _app_key,
                     AccessKeySecret = _app_secret,
+                    //Endpoint = "imagesearch.cn-shanghai.aliyuncs.com",
                     Endpoint = "imagesearch.cn-shanghai.aliyuncs.com",
                     RegionId = "cn-shanghai"
                 };
@@ -35,6 +36,8 @@ namespace molilian.core
                 {
                     PicContentObject = new MemoryStream(bytes),
                     Pid = pid,
+                    Crop = true,
+                    Num = 20,
                     Fields = "itemId,Url,CouponShareUrl,DeeplinkUrl,DeeplinkCouponShareUrl,UserType,ShopTitle,Title,PicUrl,ReservePrice,PriceAfterCoupon,CouponAmount,CouponStartTime,CouponEndTime,Volume,Provcity"
                 };
 

+ 111 - 0
molilian.core/Plus/SystemMonitor.cs

@@ -0,0 +1,111 @@
+using dodohold.core;
+using Microsoft.Extensions.Logging;
+using System.Diagnostics;
+using System.Text;
+
+
+namespace molilian.core
+{
+    public static class SystemMonitor
+    {
+        private static Timer _monitorTimer;
+        public static void StartMonitoring(int intervalSeconds = 30)
+        {
+            _monitorTimer = new Timer(
+                CollectMetrics,
+                null,
+                TimeSpan.Zero,
+                TimeSpan.FromSeconds(intervalSeconds)
+            );
+        }
+
+        private static void CollectMetrics(object state)
+        {
+            try
+            {
+                var metrics = new StringBuilder();
+
+                // 线程池信息
+                ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxIoThreads);
+                ThreadPool.GetAvailableThreads(out int availWorkerThreads, out int availIoThreads);
+                ThreadPool.GetMinThreads(out int minWorkerThreads, out int minIoThreads);
+
+                var usedWorkerThreads = maxWorkerThreads - availWorkerThreads;
+                var usedIoThreads = maxIoThreads - availIoThreads;
+
+                metrics.AppendLine("=== Thread Pool Stats ===");
+                metrics.AppendLine($"Worker Threads: {usedWorkerThreads}/{maxWorkerThreads} (used/max)");
+                metrics.AppendLine($"IO Threads: {usedIoThreads}/{maxIoThreads} (used/max)");
+                metrics.AppendLine($"Min Worker Threads: {minWorkerThreads}");
+                metrics.AppendLine($"Min IO Threads: {minIoThreads}");
+                metrics.AppendLine($"Thread Pool Queue Length: {ThreadPool.PendingWorkItemCount}");
+                metrics.AppendLine();
+
+                // 内存信息
+                var process = Process.GetCurrentProcess();
+                var gcInfo = GC.GetGCMemoryInfo();
+
+                metrics.AppendLine("=== Memory Stats ===");
+                metrics.AppendLine($"Working Set: {process.WorkingSet64 / 1024 / 1024} MB");
+                metrics.AppendLine($"Private Memory: {process.PrivateMemorySize64 / 1024 / 1024} MB");
+                metrics.AppendLine($"GC Heap Size: {GC.GetTotalMemory(false) / 1024 / 1024} MB");
+                metrics.AppendLine($"Gen 0 Collections: {GC.CollectionCount(0)}");
+                metrics.AppendLine($"Gen 1 Collections: {GC.CollectionCount(1)}");
+                metrics.AppendLine($"Gen 2 Collections: {GC.CollectionCount(2)}");
+                metrics.AppendLine($"Memory Load: {gcInfo.MemoryLoadBytes / 1024 / 1024} MB");
+
+                // 记录日志
+                _ = new LoggerLibrary("debug", "metrics").Info(metrics.ToString()).SaveAsync();
+
+                // 检查是否需要报警
+                CheckAlertConditions(
+                    usedWorkerThreads, maxWorkerThreads,
+                    process.WorkingSet64,
+                    ThreadPool.PendingWorkItemCount
+                );
+            }
+            catch (Exception ex)
+            {
+                _ = new LoggerLibrary("debug", "metrics_error")
+                    .Info($"Error collecting system metrics: {ex}").SaveAsync();
+            }
+        }
+
+        private static void CheckAlertConditions(
+            int usedWorkerThreads,
+            int maxWorkerThreads,
+            long workingSet,
+            long pendingWork)
+        {
+            var alerts = new List<string>();
+
+            // 线程池使用率超过80%
+            if ((double)usedWorkerThreads / maxWorkerThreads > 0.8)
+            {
+                alerts.Add($"High thread pool usage: {usedWorkerThreads}/{maxWorkerThreads}");
+            }
+
+            // 内存使用超过2GB
+            if (workingSet > 2L * 1024 * 1024 * 1024)
+            {
+                alerts.Add($"High memory usage: {workingSet / 1024 / 1024} MB");
+            }
+
+            // 线程池队列堆积
+            if (pendingWork > 100)
+            {
+                alerts.Add($"High thread pool queue length: {pendingWork}");
+            }
+
+            if (alerts.Any())
+            {
+                NotifyCore.Notify($"System alerts:\n{string.Join("\n", alerts)}");
+            }
+        }
+
+        public static void StopMonitoring()
+        {
+            _monitorTimer?.Dispose();
+        }
+    }
+}

+ 10 - 1
molilian.core/middleware/CustomToken.cs

@@ -1,7 +1,9 @@
-using dodohold.core;
+using CSRedis;
+using dodohold.core;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.OpenApi.Models;
 using Swashbuckle.AspNetCore.SwaggerGen;
+using YunhuiKit;
 
 namespace molilian.core
 {
@@ -38,6 +40,13 @@ namespace molilian.core
             TimerScheduler timerScheduler = new TimerScheduler(taskContainers);
             timerScheduler.Start();
 
+            SystemMonitor.StartMonitoring(30);
+
+            var connstr = Environment.GetEnvironmentVariable("RedisConfig") ?? throw new ArgumentNullException("找不到对应的RedisConfig配置!");
+            RedisKit.Initialize(connstr);
+
+
+
             //services.AddMvc(option =>
             //{
             //    option.Filters.Add(typeof(MyAuthorizationFactory.MyActionFilter));

+ 1 - 1
molilian.core/molilian.core.csproj

@@ -25,7 +25,7 @@
     <PackageReference Include="IP2Region.Net" Version="2.0.2" />
     <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
     <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
-    <PackageReference Include="YunhuiKit" Version="0.0.3" />
+    <PackageReference Include="YunhuiKit" Version="0.0.5" />
   </ItemGroup>
 
   <ItemGroup>

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است