0

我正在开发一个使用 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()
4

1 回答 1

1

Polly's.ExecuteAsync()返回一个Task. 使用 any Task,您可以调用.Wait()它(或其他阻塞方法)以同步阻塞,直到它完成或抛出异常。

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

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

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

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

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


如果您的唯一目的是在某处记录消息发布失败,并且您不关心该记录是否在IJob.Execute(...)返回之前发生,则还有另一种选择。在这种情况下.Wait(),您可以将延续任务链接到ExecuteAsync()using上,而不是 using .ContinueWith(...),并在那里处理任何登录。我们采用这种方法,并将失败的消息发布到一个特殊的“消息医院”——捕获足够的信息,以便我们可以选择是否在适当的时候再次重新发布该消息。这种方法是否有价值取决于永不丢失信息对您的重要性。


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

于 2016-09-05T17:23:59.917 回答