views:

159

answers:

2

I need to find ways to add retry mechanism to my DB calls in case of timeouts, LINQ to SQL is used to call some sprocs in my code...

using (MyDataContext dc = new MyDataContext())
{
    int result = -1; //denote failure
    int count = 0;

    while ((result < 0) && (count < MAX_RETRIES))
    {
        result = dc.myStoredProc1(...);
        count++;
    }

    result = -1;
    count  = 0;
    while ((result < 0) && (count < MAX_RETRIES))
    {
        result = dc.myStoredProc2(...);
        count++;
    }

    ...

    ...
}

Not sure if the code above is right or posed any complications.

It'll be nice to throw an exception after MAX_RETRIES has reached, but I dunno how and where to throw them appropriately :-)

Any helps appreciated.

A: 

Personally, I would use recursion here. It makes for cleaner code since the only "extra code" you have is a parameter into a function. For example:

private MyResult Foo(MyParameters mp, int repeatCall)
{
    var result = null;

    try
    {
        result = mp.dc.myStoredProc(...);
    }
    catch (MyException err)
    {
        if (repeatCall > 0)
        {
            result = Foo(mp, repeatCall - 1);
        }
        else
        {
            throw;
        }
    }

    return result;
}

This is an ideal example for recursion, I think. Whatever is calling this need not be concerned with the looping and it makes MUCH cleaner code.

Jaxidian
FWIW, I just updated this to respond to the updated question.
Jaxidian
Thanks, but the subtlety here is that I do have a series of sprocs to call in order to complete an action due to the funny design (not by me) of the system underneath, so your solution may not be the exact match but still very nice to know.
codemonkie
The add an additional parameter to either identify the sproc or a delegate if each sproc maps to a function.
Jaxidian
+2  A: 

If you get a timeout from your database, it's not very likely that it's going to respond in a timely fashion a few miliseconds later.

Retrying in a tight loop as you suggest is likely to make a bad situation worse because you would be placing an undue burden on the database server, as well as tying up a thread in the calling code. It would be safer to introduce a wait time between each retry.

For more advanced scenarios, you could consider a progressive wait pattern where you retry more frequently in the beginning and then with longer and longer intervals if you still get timeouts.

You may also want to look into the Circuit Breaker design pattern from the book Release It!, as well as many of the other patterns and anti-patterns described in that book.

The State pattern is a good fit for implementing Circuit Breaker.

Mark Seemann
Thanks Mark, you are indeed right, there are actually some design flaws in the DB tables I must say from donkey years, and we cannot afford to change that for now so have to live with it, there are some bad consequences such as timeout or connections depleted occasionally.For the given situation I'll take your advice to introduce a wait time between each retry.Does that imply I'm better off to have a thread to handle that since that looks like a blocking call to me?
codemonkie
From a stability viewpoint, introducing retries with wait times would definitely create blocking threads, so you run the risk of saturating the system when load is high. That's why Circuit Breaker is a better option, but that means that you will need to handle errors (and potential retry logic) somewhere else in the application. If you have asynchronous operations, you should consider putting the retries on a queue and have an async process perform the retries. That wouldn't block an arbitrary number of threads - only as many threads as you assign to the async retry service.
Mark Seemann