如何在方法中使用await关键字而不更改方法async

时间:2016-09-05 14:57:55

标签: c#-4.0 async-await quartz.net polly

我正在开发一个预定作业,使用Quartz.net将消息发送到消息队列。 IJob的Execute方法不是异步的。所以我不能使用异步任务。但是我想用await关键字调用一个方法。

请在下面找到我的代码。不确定我是否做得对。有人可以帮我这个吗?

private async Task PublishToQueue(ChangeDetected changeDetected)
{
    _logProvider.Info("Publish to Queue started");

    try
    {
       await _busControl.Publish(changeDetected);

        _logProvider.Info($"ChangeDetected message published to RabbitMq. Message");
    }
    catch (Exception ex)
    {
        _logProvider.Error("Error publishing message to queue: ", ex);

        throw;
    }
}

public class ChangedNotificatonJob : IJob
{
    public void Execute(IJobExecutionContext context)
    {
                    //Publish message to queue
                    Policy
                        .Handle<Exception>()
                        .RetryAsync(3, (exception, count) =>
                        {
                            //Do something for each retry
                        })
                        .ExecuteAsync(async () =>
                        {
                            await PublishToQueue(message);
                        });
    }
}

这是正确的方法吗?我用过.GetAwaiter();

Policy
        .Handle<Exception>()
        .RetryAsync(_configReader.RetryLimit, (exception, count) =>
        {
            //Do something for each retry
        })
        .ExecuteAsync(async () =>
        {
            await PublishToQueue(message);
        }).GetAwaiter()

1 个答案:

答案 0 :(得分:1)

Polly&#39; .ExecuteAsync()返回Task。对于任何Task,您只需在其上调用.Wait()(或其他阻塞方法)即可同步阻塞,直到完成或抛出异常。

正如您所观察到的,由于IJob.Execute(...)不是async,因此您无法使用await,因此您别无选择,只能同步阻止任务,如果你想在IJob.Execute(...)返回之前发现成功或否则发布。

.Wait()将导致任务中的任何异常被重新引发,并包含在AggregateException中。如果所有Polly-orchestrated重试都失败,则会发生这种情况。

您需要决定如何处理该异常:

  • 如果您希望调用者处理它,请重新抛出它或者不要捕获它并让它在Quartz作业之外级联。

  • 如果您想在从IJob.Execute(...)返回之前处理它,那么您需要在整个try {} catch {}周围.ExecuteAsync(...).Wait()。或者考虑一下Polly的.ExecuteAndCaptureAsync(...)语法:它避免了你必须提供外部try-catch,而是将执行的最终结果放入PolicyResult实例中。请参阅Polly doco

如果您的唯一目的是记录消息发布失败的地方,并且您不关心在IJob.Execute(...)返回之前是否发生了日志记录,还有另一种选择。在这种情况下,您可以使用.Wait()将延续任务链接到ExecuteAsync(),而不是使用.ContinueWith(...),并处理其中的任何日志记录。我们采用这种方法,并将失败的消息发布到一个特殊的消息医院&#39; - 捕获足够的信息,以便我们可以选择是否在以后再次重新发布该消息(如果适用)。这种方法是否有价值取决于它对你永远不会失去信息的重要性。

编辑:GetAwaiter()无关紧要。它不会神奇地让你开始在非await方法中使用async