|
|
@@ -185,27 +185,39 @@ namespace molilian.core
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ private static readonly TimeSpan QpsWindow = TimeSpan.FromSeconds(1);
|
|
|
+
|
|
|
private static bool TryAcquireQps(TkPoolDTO account)
|
|
|
{
|
|
|
if (account == null) return false;
|
|
|
|
|
|
- return SpecialBusinessRateLimiter.TryAcquire(
|
|
|
- $"tk_pool_qps:{account.id}",
|
|
|
- account.qps_limit,
|
|
|
- TimeSpan.FromSeconds(1));
|
|
|
+ long acquiredSinceTicks = DateTime.UtcNow.Ticks;
|
|
|
+ if (!SpecialBusinessRateLimiter.TryAcquire($"tk_pool_qps:{account.id}", account.qps_limit, QpsWindow))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // cis_limit:N 毫秒内只允许 1 次;未满足间隔时归还刚占用的 QPS 名额
|
|
|
+ if (account.cis_limit > 0 &&
|
|
|
+ !SpecialBusinessRateLimiter.TryAcquire($"tk_pool_cis:{account.id}", 1, TimeSpan.FromMilliseconds(account.cis_limit)))
|
|
|
+ {
|
|
|
+ if (account.qps_limit > 0)
|
|
|
+ SpecialBusinessRateLimiter.Release($"tk_pool_qps:{account.id}", QpsWindow, acquiredSinceTicks);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// 归还分配账号时占用的 QPS 名额(转链未提交到 endpoint 时调用)
|
|
|
+ /// 归还分配账号时占用的 QPS / 请求间隔名额(转链未提交到 endpoint 时调用)
|
|
|
/// </summary>
|
|
|
public static void ReleaseQps(TkPoolDTO account, long acquiredSinceTicks)
|
|
|
{
|
|
|
- if (account == null || account.qps_limit <= 0) return;
|
|
|
+ if (account == null) return;
|
|
|
+
|
|
|
+ if (account.qps_limit > 0)
|
|
|
+ SpecialBusinessRateLimiter.Release($"tk_pool_qps:{account.id}", QpsWindow, acquiredSinceTicks);
|
|
|
|
|
|
- SpecialBusinessRateLimiter.Release(
|
|
|
- $"tk_pool_qps:{account.id}",
|
|
|
- TimeSpan.FromSeconds(1),
|
|
|
- acquiredSinceTicks);
|
|
|
+ if (account.cis_limit > 0)
|
|
|
+ SpecialBusinessRateLimiter.Release($"tk_pool_cis:{account.id}", TimeSpan.FromMilliseconds(account.cis_limit), acquiredSinceTicks);
|
|
|
}
|
|
|
|
|
|
private static async Task<bool> FilterNodesAsync(TkPoolDTO item, TkAction action)
|