如何在不更改异步方法的情况下在方法中使用 await 关键字
How to use await keyword inside a method without changing the method async
我正在开发一个计划作业以使用 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()
波莉 .ExecuteAsync()
returns 一个 Task
。对于任何 Task
,您只需对其调用 .Wait()
(或其他阻塞方法)以同步阻塞,直到它完成或抛出异常。
如您所见,由于 IJob.Execute(...)
不是 async
,您不能使用 await
,因此您别无选择,只能在任务上同步阻塞,如果您想在 IJob.Execute(...)
returns.
之前发现发布的成功与否
.Wait()
将导致任务中的任何异常被重新抛出,包裹在 AggregateException
中。如果所有 Polly 编排的重试都失败,就会发生这种情况。
您需要决定如何处理该异常:
如果你想让调用者处理它,重新抛出它或者不捕获它,让它级联到 Quartz 作业之外。
如果你想在从IJob.Execute(...)
返回之前处理它,你需要一个try {} catch {}
围绕整个.ExecuteAsync(...).Wait()
。或者考虑 Polly 的 .ExecuteAndCaptureAsync(...)
语法:它通过将执行的最终结果放入 PolicyResult
实例中来避免您必须提供外部 try-catch。参见Polly doco。
如果您的唯一目的是在消息发布失败的地方记录日志,并且您不关心该日志记录是否发生在 IJob.Execute(...)
returns 之前,则还有另一种选择。在这种情况下,您可以使用 .ContinueWith(...)
将延续任务链接到 ExecuteAsync()
,并在其中处理任何日志记录,而不是使用 .Wait()
。我们采用这种方法,并将失败的消息发布捕获到一个特殊的 'message hospital' - 捕获足够的信息,以便我们可以选择是否在适当的时候再次重新发布该消息。这种方法是否有价值取决于永不丢失消息对您的重要性。
编辑:GetAwaiter()
无关紧要。它不会神奇地让您开始在非 async
方法中使用 await
。
我正在开发一个计划作业以使用 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()
波莉 .ExecuteAsync()
returns 一个 Task
。对于任何 Task
,您只需对其调用 .Wait()
(或其他阻塞方法)以同步阻塞,直到它完成或抛出异常。
如您所见,由于 IJob.Execute(...)
不是 async
,您不能使用 await
,因此您别无选择,只能在任务上同步阻塞,如果您想在 IJob.Execute(...)
returns.
.Wait()
将导致任务中的任何异常被重新抛出,包裹在 AggregateException
中。如果所有 Polly 编排的重试都失败,就会发生这种情况。
您需要决定如何处理该异常:
如果你想让调用者处理它,重新抛出它或者不捕获它,让它级联到 Quartz 作业之外。
如果你想在从
IJob.Execute(...)
返回之前处理它,你需要一个try {} catch {}
围绕整个.ExecuteAsync(...).Wait()
。或者考虑 Polly 的.ExecuteAndCaptureAsync(...)
语法:它通过将执行的最终结果放入PolicyResult
实例中来避免您必须提供外部 try-catch。参见Polly doco。
如果您的唯一目的是在消息发布失败的地方记录日志,并且您不关心该日志记录是否发生在 IJob.Execute(...)
returns 之前,则还有另一种选择。在这种情况下,您可以使用 .ContinueWith(...)
将延续任务链接到 ExecuteAsync()
,并在其中处理任何日志记录,而不是使用 .Wait()
。我们采用这种方法,并将失败的消息发布捕获到一个特殊的 'message hospital' - 捕获足够的信息,以便我们可以选择是否在适当的时候再次重新发布该消息。这种方法是否有价值取决于永不丢失消息对您的重要性。
编辑:GetAwaiter()
无关紧要。它不会神奇地让您开始在非 async
方法中使用 await
。