Reputation: 1020
Background
In my C# project (.NET 5.0), I am using NPoco (an ORM) to run SQL commands. I am then looking to execute the calls via a retry policy using Polly (e.g. if certain transient SQL errors occur, then retry up to N times).
For synchronous calls, this is straightforward. However, for asynchronous calls, I can see at least 3 ways to do it. Essentially, the difference between my 3 ways is in whether or not they use Polly's and NPoco's own synchronous method or asynchronous methods. Note that I cannot see the internals of these methods.
The question
All the below methods build OK, and appear to work. My question is - is there any difference (functionally, reliability or performance-wise) between these approaches?
Code samples
Note that a Polly policy has a synchronous method: T Execute(Func<T> action)
and an asynchronous method: Task<T> ExecuteAsync(Func<Task<T>> action)
Here is my synchronous method (synchronous Polly and NPoco methods):
public T GetScalar<T>(string sql, params object[] args)
{
return _policy.Execute(() => _npoco.ExecuteScalar<T>(sql, args));
}
Here is my asynchronous method #1 (asynchronous Polly and NPoco methods):
public async Task<T> GetScalarAsync1<T>(string sql, params object[] args)
{
return await _policy.ExecuteAsync(() => _npoco.ExecuteScalarAsync<T>(sql, args));
}
Here is my asynchronous method #2 (asynchronous Polly and synchronous NPoco methods):
public async Task<T> GetScalarAsync2<T>(string sql, params object[] args)
{
return await _policy.ExecuteAsync(() => Task.Run(() => _npoco.ExecuteScalar<T>(sql, args)));
}
Here is my asynchronous method #3 (synchronous Polly and NPoco methods, run as task):
public async Task<T> GetScalarAsync3<T>(string sql, params object[] args)
{
return await Task.Run(() => _policy.Execute(() => _npoco.ExecuteScalar<T>(sql, args)));
}
Upvotes: 1
Views: 231
Reputation: 22829
You should use this version since ExecuteScalarAsync
most probably can take advantage of non-blocking async I/O:
await _policy.ExecuteAsync(() => _npoco.ExecuteScalarAsync<T>(sql, args));
or you could use async
-await
inside the ExecuteAsync
as well
await _policy.ExecuteAsync(async () => await _npoco.ExecuteScalarAsync<T>(sql, args));
By definition Task.Run
:
Queues the specified work to run on the ThreadPool and returns a task or
Task<TResult>
handle for that work
In other words it is not designed for async I/O rather to kick off a CPU intensive computation in the background.
Upvotes: 1