监控超时同步方法 [英] Monitoring a synchronous method for timeout
问题描述
我在寻找一种有效的方式抛出一个超时异常,如果一个同步的方法耗时过长执行。我见过一些样品,但没有相当多我想要做什么。
我需要做的就是
- 检查同步方法不超过其SLA
- 如果它抛出一个超时异常
我的不可以有权终止同步方法,如果执行时间过长。 (多重故障跳闸断路器,防止连锁故障)
我的解决方案至今如下所示。请注意,我传递的CancellationToken的同步方法,希望它会履行对超时取消请求。另外我的解决方案返回可以然后等我的调用代码根据需要等待一个任务。
我担心的是,这个代码创建每个方法是监控两个任务。我认为,TPL将管理好这一点,但我想确认。
这是否有道理?有没有更好的办法做到这一点。
私人任务TimeoutSyncMethod(动作<的CancellationToken> syncAction,时间跨度超时)?
{
变种CTS =新CancellationTokenSource();
变种外= Task.Run(()=>
{
试
{
//开始同步方法 - 传递一个取消令牌
变种内= Task.Run(()=> syncAction(cts.Token),cts.Token);(!inner.Wait(超时))
如果
{
//尝试给同步方法有机会grecefully $中止b $ b cts.Cancel();
//有超时不管同步方法做什么 - 所以扔
抛出新TimeoutException异常(超时等待方法后+超时);
}
}
终于
{
cts.Dispose();
}
},cts.Token);
的回报外,
}
修改:
使用@提摩太的答案我现在用这个。虽然没有显著较少的代码就更加清晰。 !谢谢
私人任务TimeoutSyncMethod(动作<的CancellationToken> syncAction,时间跨度超时)
{
变种CTS =新CancellationTokenSource();
变种内= Task.Run(()=> syncAction(cts.Token),cts.Token);
VAR延迟= Task.Delay(超时,cts.Token);
VAR timeoutTask = Task.WhenAny(内,延迟).ContinueWith(T =>
{
试
{
如果(内! IsCompleted)
{
cts.Cancel();
抛出新TimeoutException异常(超时等待的方法后,+超时);
}
}
最后
{
cts.Dispose();
}
},cts.Token);
返回timeoutTask;
}
如果你有一个工作
名为任务
,你可以这样做:
VAR延迟= Task.Delay(TimeSpan.FromSeconds(3));
VAR timeoutTask = Task.WhenAny(任务延迟);
如果 timeoutTask.Result
最终被任务
,那么它没有超时。否则,它是延迟
并没有超时。
我不知道这是怎么回事相同的行为与你已经实现,但它内置的方式来做到这一点。
I'm looking for an efficient way to throw a timeout exception if a synchronous method takes too long to execute. I've seen some samples but nothing that quite does what I want.
What I need to do is
- Check that the sync method does exceed its SLA
- If it does throw a timeout exception
I do not have to terminate the sync method if it executes for too long. (Multiple failures will trip a circuit breaker and prevent cascading failure)
My solution so far is show below. Note that I do pass a CancellationToken to the sync method in the hope that it will honor a cancellation request on timeout. Also my solution returns a task that can then be awaited on etc as desired by my calling code.
My concern is that this code creates two tasks per method being monitoring. I think the TPL will manage this well, but I would like to confirm.
Does this make sense? Is there a better way to do this?
private Task TimeoutSyncMethod( Action<CancellationToken> syncAction, TimeSpan timeout )
{
var cts = new CancellationTokenSource();
var outer = Task.Run( () =>
{
try
{
//Start the synchronous method - passing it a cancellation token
var inner = Task.Run( () => syncAction( cts.Token ), cts.Token );
if( !inner.Wait( timeout ) )
{
//Try give the sync method a chance to abort grecefully
cts.Cancel();
//There was a timeout regardless of what the sync method does - so throw
throw new TimeoutException( "Timeout waiting for method after " + timeout );
}
}
finally
{
cts.Dispose();
}
}, cts.Token );
return outer;
}
Edit:
Using @Timothy's answer I'm now using this. While not significantly less code it is a lot clearer. Thanks!
private Task TimeoutSyncMethod( Action<CancellationToken> syncAction, TimeSpan timeout )
{
var cts = new CancellationTokenSource();
var inner = Task.Run( () => syncAction( cts.Token ), cts.Token );
var delay = Task.Delay( timeout, cts.Token );
var timeoutTask = Task.WhenAny( inner, delay ).ContinueWith( t =>
{
try
{
if( !inner.IsCompleted )
{
cts.Cancel();
throw new TimeoutException( "Timeout waiting for method after " + timeout );
}
}
finally
{
cts.Dispose();
}
}, cts.Token );
return timeoutTask;
}
If you have a Task
called task
, you can do this:
var delay = Task.Delay(TimeSpan.FromSeconds(3));
var timeoutTask = Task.WhenAny(task, delay);
If timeoutTask.Result
ends up being task
, then it didn't timeout. Otherwise, it's delay
and it did timeout.
I don't know if this is going to behave identically to what you have implemented, but it's the built-in way to do this.
这篇关于监控超时同步方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!