我有一个这样执行的政策:
_logger.LogDebug($"Got the policy for {tenant.TenantCode}");
policy.Execute(
() =>
{
_logger.LogDebug($"Calling _domainEventDLA.GetOldestEvent {tenant.TenantCode}");
domainEvent = _domainEventDLA.GetOldestEvent(tenant);
_logger.LogDebug($"Calling _domainEventDLA.GetOldestEvent {tenant.TenantCode}");
}
);
我将超时设置为3秒,并且收到了Polly超时异常。执行中的方法花费不到100毫秒。
在日志中,我看到第一个日志行(为...指定了策略),而下一个记录的事件是3秒后的超时异常。在实际方法调用(调用_domainEventDLA ...)之前,我从未在执行中看到日志行。
这是超时策略:
var timeoutPolicy = Policy
.Timeout(3, timeoutStrategy: TimeoutStrategy.Pessimistic,
onTimeout: (context, timespan, task) =>
{
_logger.LogError(
$"A database timeout occured after {timespan.TotalSeconds} seconds, for tenant {tenant.TenantCode}.");
});
这是一个多线程应用程序,因此其他线程可能正在使用相同的策略。
有什么想法吗?
答案 0 :(得分:0)
可能您正在遇到线程饥饿。 Polly项目向following explanation提供了有关在高度并行性情况下使用同步悲观超时策略的信息:
对于同步执行,调用线程从“原本无法超时”的操作中“退出”的能力是有代价的:要允许当前线程退出,策略将执行用户委托作为ThreadPool线程上的任务。
由于此费用在可能处理的并发请求数可能很高或无限制的情况下,我们不建议使用悲观的同步TimeoutPolicy。在这种高/无限制的情况下,该费用(实际上使数目增加了一倍)的线程数可能非常昂贵。
我们建议使用悲观同步TimeoutPolicy,同时明确限制该代码路径上调用的并行性。控制并行性的选项包括:
- 在“超时”策略的上游使用Polly BulkheadPolicy(这是一种并行控制)
- 在“超时”策略的上游使用并发限制的TaskScheduler
- 在TimeoutPolicy的上游使用断路器策略,并将断路器配置为在太多下游呼叫超时时中断。这样可以防止在超时时对下游系统(和阻塞线程)进行过多的呼叫
- 调用环境的任何其他内置并行控制。
您的代码似乎正在经历线程匮乏:似乎在调度已执行委托的任务时,ThreadPool无法提供线程来执行超时。
线程匮乏当然可以发生在任何高度并行化的应用程序中。了解应用程序的峰值负载并选择是否在不可预测的事件开始发生之前限制并行性(如discussed on the Polly blog)是一种有用的做法。