HiveBrain v1.2.0
Get Started
← Back to all entries
debugcsharpMinor

General Retry Strategy

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
strategyretrygeneral

Problem

Let’s say we copy some file using retry strategy (it might be blocked, etc.):

class Processor
{
    public void CopyData() =>
        CopyData(Try.Slow);

    public void CopyData(Try loop) =>
        loop.Execute(() => 
            File.Copy(@"c\a.txt", @"c:\b.txt"));
}


What do you think about names chosen for the following library code identifiers? Would you name them differently?

public abstract class Try
{
    public static Try Repeat(params int[] delays) => new Repeat(delays);
    public static readonly Try Never = Repeat();
    public static readonly Try Once = Repeat(0);
    public static readonly Try Slow = Repeat(0, 500, 1500, 4500, 12000);
    public static readonly Try Fast = Repeat(0, 50, 150, 450, 1200);
    public abstract void Execute(Action action);
}

class Repeat : Try
{
    IReadOnlyList Delays { get; }

    public Repeat(params int[] delays)
    {
        Delays = delays;
    }

    public override void Execute(Action action)
    {
        for(int i=0; i< Delays.Count; i++)
            try
            {
                Thread.Sleep(Delays[i]);
                action();
                return;
            }
            catch
            {
                if (i == Delays.Count - 1)
                    throw;
            }
    }
}

Solution

I think this would be more useful if the user could specify an interval and how many times he wants to retry like:

public static Try Repeat(int dalay, int count) 
    => new Repeat(Enumerable.Repeat(delay, count));


or if he could specify a count and the increment function:

public static Try Repeat(int count, Func increment) 
    => new Repeat(Enumerable.Range(1, count + 1).Select(x => increment(x));


where the increment could be:

x => x * 20


I wouldn't provide such members as Fast or Slow because they are very subjective and what for you currently is slow might be in my application still too fast.

Never does not make any sense ;-) Why should I want to never try to execute something? I might as well not write the code at all if it shouldn't run :-P

One more thoght. How about specifying the retry strategy via a generic argument:

class SlowTry : Repeat
{
    public SlowTry() : base(0, 500, 1500, 4500, 12000) { }
}


the Try becomes this:

public abstract class Try
{
    ... stays the same

    public static void Execute(Action action) where TStrategy : Try, new()
    {
        new TStrategy().Execute(action);
    }
}


use:

Try.Execute(() => File.Copy(@"c\a.txt", @"c:\b.txt"));


This way the user can easier specify his strategy.

Code Snippets

public static Try Repeat(int dalay, int count) 
    => new Repeat(Enumerable.Repeat(delay, count));
public static Try Repeat(int count, Func<int, int> increment) 
    => new Repeat(Enumerable.Range(1, count + 1).Select(x => increment(x));
x => x * 20
class SlowTry : Repeat
{
    public SlowTry() : base(0, 500, 1500, 4500, 12000) { }
}
public abstract class Try
{
    ... stays the same

    public static void Execute<TStrategy>(Action action) where TStrategy : Try, new()
    {
        new TStrategy().Execute(action);
    }
}

Context

StackExchange Code Review Q#140166, answer score: 3

Revisions (0)

No revisions yet.