I have some async methods I want to try a set number of times until they return true or the max attempts have been reached, with a delay in between. I've been able to get the outcome I desire, but have not been able to reduce the redundancy.
The functions return Task<bool>.
The below code is what I'm trying to generalize (as only the function call line is different)
for (int attempts = 0; attempts < numOfTaskAttempts; ++attempts)
{
if (!await UpdateSingleUserStatistic(sendingPlayer, PlayfabServerKeys.DailyPuzzle, request.score))
await Task.Delay(taskAttemptDelay);
else
break
}
I tried to generalize by creating methods passing delegates (below) since the only one line differs, but for some reason, can't see a way to generalize them.
On searching this site, I first tried passing a Task instead of a delegate, but that just ran the task once.
I wrote the below methods where the signature of the Func changes as do the string arguments provided. I can't seem to find a way to make them more generic (i.e. have just one method and pass a task and/or a delegate).
private static async Task<bool> CallAsyncMethodWithRetries(
Func<Task<bool>> callback, int maxAttempts = numOfTaskAttempts,
int delay = taskAttemptDelay)
{
int numOfTries = 0;
while (!await callback() && ++numOfTries < maxAttempts)
await Task.Delay(delay);
return numOfTries < maxAttempts;
}
private static async Task<bool> CallAsyncMethodWithRetries(
Func<string, Task<bool>> callback, string arg,
int maxAttempts = numOfTaskAttempts, int delay = taskAttemptDelay)
{
int numOfTries = 0;
while (!await callback(arg) && ++numOfTries < maxAttempts)
await Task.Delay(delay);
return numOfTries < maxAttempts;
}
private static async Task<bool> CallAsyncMethodWithRetries(
Func<string, string, Task<bool>> callback, string arg1, string arg2,
int maxAttempts = numOfTaskAttempts, int delay = taskAttemptDelay)
{
int numOfTries = 0;
while (!await callback(arg1, arg2) && ++numOfTries < maxAttempts)
await Task.Delay(delay);
return numOfTries < maxAttempts;
}
How they are called:
bool isSuccess = false;
if (await CallAsyncMethodWithRetries(CreateAndSetTopPuzzlePlayers))
if (await CallAsyncMethodWithRetries(SetTitleData, PlayfabServerKeys.DailyPuzzle, dailyPuzzle))
isSuccess = await CallAsyncMethodWithRetries(ResetLeaderboard, PlayfabServerKeys.DailyPuzzle);
Any way to reduce the redundant code would be appreciated. I'm still fairly new at async programming, so the solution could be right in front of me and I probably wouldn't know it.