我想爲RabbitMQ C#客戶端的BasicPublish方法編寫一個超時函數。出於很多原因,有時隊列被阻塞,或者兔子掉下來或者其他什麼。但是我想知道發佈何時失敗。我不想因任何原因阻止該網站。如何寫短暫和重複動作的超時?
我很擔心在任務或線程中添加了一個超時,爲簡單的發佈添加開銷,我們在生產中做了數百萬次。
有沒有人有想法如何寫一個快速阻塞方法的快速超時爲BasicPublish?
說明:另外我在.Net 4中工作,我沒有異步。
我想爲RabbitMQ C#客戶端的BasicPublish方法編寫一個超時函數。出於很多原因,有時隊列被阻塞,或者兔子掉下來或者其他什麼。但是我想知道發佈何時失敗。我不想因任何原因阻止該網站。如何寫短暫和重複動作的超時?
我很擔心在任務或線程中添加了一個超時,爲簡單的發佈添加開銷,我們在生產中做了數百萬次。
有沒有人有想法如何寫一個快速阻塞方法的快速超時爲BasicPublish?
說明:另外我在.Net 4中工作,我沒有異步。
波利有TimeoutPolicy瞄準的正是這種情況。
波莉的TimeoutStrategy.Optimistic
接近@ ThiagoCustodio的答案,但它也正確地配置CancellationTokenSource
。然而,RabbitMQ的C#客戶端不會(在撰寫本文時)提供BasicPublish()
過載,因此需要使用CancellationToken
,因此此方法不相關。
波莉TimeoutStrategy.Pessimistic
旨在場景,如BasicPublish()
,要強加給委託其不有CancellationToken
支持超時。
波莉TimeoutStrategy.Pessimistic
:
[1]允許調用線程超時上(從行走等待外)的執行,即使執行委託不支持取消。
[2]以一個額外的任務/線程爲代價(在同步執行中),併爲您進行管理。
[3]也captures the timed-out Task
(你已經離開的任務)。這對於日誌記錄是有價值的,並且是必需的以避免UnobservedTaskExceptions - 特別是在.NET4.0中,其中UnobservedTaskException can bring down your entire process。
簡單的例子:
Policy.Timeout(TimeSpan.FromSeconds(10), TimeoutStrategy.Pessimistic).Execute(() => BasicPublish(...));
完整的示例適當避免UnobservedTaskException
S:
Policy timeoutPolicy = Policy.Timeout(TimeSpan.FromSeconds(10), TimeoutStrategy.Pessimistic, (context, timespan, task) =>
{
task.ContinueWith(t => { // ContinueWith important!: the abandoned task may very well still be executing, when the caller times out on waiting for it!
if (t.IsFaulted)
{
logger.Error($"{context.PolicyKey} at {context.ExecutionKey}: execution timed out after {timespan.TotalSeconds} seconds, eventually terminated with: {t.Exception}.");
}
else
{
// extra logic (if desired) for tasks which complete, despite the caller having 'walked away' earlier due to timeout.
}
});
});
timeoutPolicy.Execute(() => BasicPublish(...));
爲了避免在RabbitMQ的不可用的情況下建立太多的併發未決任務/線程,您可以使用Bulkhead Isolation policy來限制並行和/或CircuitBreaker,以防止撥打電話一段時間,你會發現一定程度的故障。這些可以與使用PolicyWrap
的TimeoutPolicy相結合。
我會說最簡單的方法是使用任務/取消令牌。你認爲這是一個開銷?
public static async Task WithTimeoutAfterStart(
Func<CancellationToken, Task> operation, TimeSpan timeout)
{
var source = new CancellationTokenSource();
var task = operation(source.Token);
source.CancelAfter(timeout);
await task;
}
用法:
await WithTimeoutAfterStart(
ct => SomeOperationAsync(ct), TimeSpan.FromMilliseconds(n));
你也可以使用Polly包裝你的代碼:https://github.com/App-vNext/Polly#retry和https://github.com/App-vNext/Polly#retry –
我沒有關於if任務真的創建一個線程或不創建一個線程,當它創建一個新的線程。但是,我認爲爲每個發佈創建一個線程是一個發佈操作的開銷,當一切工作正常時。圖書館Polly也有,我會調查它 – elranu
很酷。最後它只是一個封裝的重試模式。如果它們都不符合您的需求,則可以隨時編寫自己的:https://msdn.microsoft.com/en-us/library/dn589788.aspx和http://stackoverflow.com/questions/1563191/cleanest-way寫入重試邏輯 –
您可以在.NET4中使用'async' /'await'。0使用[Microsoft.BCL.Async](https://www.nuget.org/packages/Microsoft.Bcl.Async/)包。 –