0

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.

1

1 Answer 1

3

There are various ways to approach this, including, as was mentioned in a comment to the question, delegates with a variable number of arguments, and up to using reflection.

But a cleanest and in fact more functional approach in these cases is to simply have your CallAsyncMethodWithRetries take a Func<Task<bool>> as argument, and then you call it with a lambda expression that closes (as in closure) over the actual method invocation with the needed arguments, as for example:

await CallAsyncMethodWithRetries(() => ResetLeaderboard(PlayfabServerKeys.DailyPuzzle));

Here is a full example (slightly simplified re your code, I have removed argument defaults): https://dotnetfiddle.net/JVKUYP

Sign up to request clarification or add additional context in comments.

3 Comments

To be clear, you're suggesting that the OP's first method is the answer.
While my answer is, and only partially, matched by the OP's first snippet, that is just incidental, there is no answer in the OP who is rather thinking overloaded signatures: indeed, I have given an answer that was not even under the radar, and I have in fact explained what's the idea and how it works.
What do you mean by "not even under the radar"? Do you mean "not even on the radar"?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.