2017-02-16 4 views
0

Я хотел бы написать функцию таймаута для метода BasicPublish для клиента RabbitMQ C#. По многим причинам иногда очередь блокируется, или кролик не работает или что-то еще. Но я хочу определить, когда публикация не работает сразу. Я не хочу блокировать сайт по какой-либо причине.Как написать тайм-аут для коротких и многократных действий?

Я беспокоюсь, чтобы реализовать тайм-аут с помощью задачи или потоков, добавляющих накладные расходы для простой публикации, что мы делаем это миллионы раз в производстве.

У кого-нибудь есть идея, как написать быстрый тайм-аут на быстрый метод блокировки как BasicPublish?

Уточнение: Также я работаю в .Net 4, у меня нет асинхронной работы.

+0

Вы можете использовать 'async' /' await' с .NET4.0 с помощью пакета [Microsoft.BCL.Async] (https://www.nuget.org/packages/Microsoft.Bcl.Async/). –

ответ

1

Polly имеет TimeoutPolicy, направленную на именно этот сценарий.

Polly's TimeoutStrategy.Optimistic находится рядом с ответом @ ThiagoCustodio, но он также правильно устанавливает CancellationTokenSource. Однако клиент C# RabbitMQ не имеет (на момент написания) предложения перегрузки BasicPublish(), принимающей CancellationToken, поэтому этот подход не имеет отношения к делу.

Полл TimeoutStrategy.Pessimistic направлен на сценариях, такие как BasicPublish(), где вы хотите ввести тайм-аут на делегат, который не делает имеет поддержки CancellationToken.

Полл TimeoutStrategy.Pessimistic:

[1] позволяет вызывающий поток к тайм-ауту на (уйти от ожидания) исполнения, даже тогда, когда выполняются делегат не поддерживает отмену.

[2] делает это за счет дополнительной задачи/потока (в синхронных исполнениях) и управляет этим для вас.

[3] также captures the timed-out Task (задача, с которой вы ушли). Это может быть ценным для каротажа и является essential, чтобы избежать 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, чтобы предотвратить прохождение вызовов в течение периода, на вы обнаружите определенный уровень сбоев. Их можно комбинировать с TimeoutPolicy, используя PolicyWrap.

0

Я бы сказал, что самый простой способ - использовать токены задач/отмены. Как вы думаете, это накладные расходы?

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)); 
+1

Также вы можете обернуть свой код с помощью Polly: https://github.com/App-vNext/Polly#retry и https://github.com/App-vNext/Polly#retry –

+0

У меня нет больших знаний о том, если Задача действительно создает поток или нет, и когда именно он создает новый поток. Но да, я думаю, что создание Thread для каждого из них публикует накладные расходы для публикации, когда все работает нормально. Кроме того, Intersted library Polly, я исследую его – elranu

+0

Прохладный. В конце концов, это всего лишь шаблон повторной инкапсуляции. Если ни одна из них не соответствует вашим потребностям, вы всегда можете написать свой собственный: https://msdn.microsoft.com/en-us/library/dn589788.aspx и http://stackoverflow.com/questions/1563191/cleanest-way -to-write-retry-logic –

Смежные вопросы