How would you implement an unlimited retry mechanism in case internal logics fails
something like this, but here you have only one change
static void Main(string[] args)
{
ILog Log = LogManager.GetLogger(typeof(Program));
try
{
StartWorking(Log);
}
catch (Exception ex)
{
Log.Error("Main exited with error: {0}. Restarting app", ex);
Thread.Sleep(5000);
StartWorking(Log);
}
}
private static void StartWorking(ILog Log)
{
Foo t = new Foo();
t.ReadConfiguration();
t.Login();
t.StartWorking();
}
You could use a while loop:
while (true)
{
try
{
StartWorking(Log);
// No exception was thrown, exit the loop
break;
}
catch (Exception ex)
{
Log.Error("Main exited with error: {0}. Restarting app", ex);
Thread.Sleep(5000);
}
}
Note however that this is very bad practice. You definitely don't want to be doing this. Instead you should have a retry logic that after a number of retries just gives up. For example:
const int maxRetries = 5;
for (var i = 0; i < maxRetries; i++)
{
try
{
StartWorking(Log);
// No exception was thrown, exit the loop
break;
}
catch (Exception ex)
{
Log.Error("Main exited with error: {0}. Restarting app", ex);
Thread.Sleep(5000);
}
if (i == maxRetries - 1)
{
throw new Exception("Sorry, we have reached the maximum number of retries for this operation, just giving up");
}
}
Related
I am trying to use try catch in C# application but I am facing problem suppose first-time internet issue came and then again it tries to sync second-time internet came then after return statement it's going again in catch(CommunicationException comEx) block and return false.
why its happening
int SyncFailCount = 0;
private bool SyncCustomers(long TenantId, DataTable dtCusomers)
{
bool IsSyncSuccess = false;
try
{
SyncQBClient client = new SyncQBClient();
client.SynvCustomer(TenantId, dtCusomers);
SyncFailCount = 0;
IsSyncSuccess = true;
}
catch (CommunicationException comEx) // Mohan: Exception due to Internet issue
{
SyncFailCount = SyncFailCount + 1;
Thread.Sleep(300);
if (SyncFailCount <= 5)
{
SyncCustomers(TenantId, dtCusomers);
}
}
catch (TimeoutException TimeoutEx) // Mohan: Exception due to timeout from web service
{
SyncFailCount = SyncFailCount + 1;
Thread.Sleep(300);
if (SyncFailCount <= 5)
{
SyncCustomers(TenantId, dtCusomers);
}
SyncFailCount = 0;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "CashPundit", MessageBoxButtons.OK, MessageBoxIcon.Error);
SyncFailCount = 0;
}
return IsSyncSuccess;
}
If there is an exception in SyncCustomers() you will call SyncCustomers.
As far as good.
Let's pretend that your second run is good and would return True (at return IsSyncSuccess;)
And here is the problem, you are not catching the return statement in your exception handling - the True is getting lost in the catch block.
Instead of recursively calling the method, may try a while loop to get the synchronization work, no matter if there is an exception or not.
int SyncFailCount = 0;
private bool SyncCustomers(long TenantId, DataTable dtCusomers)
{
bool IsSyncSuccess = false;
// While there is no success do the loop
while (!IsSyncSuccess)
{
try
{
SyncQBClient client = new SyncQBClient();
client.SynvCustomer(TenantId, dtCusomers);
SyncFailCount = 0;
IsSyncSuccess = true;
}
catch (CommunicationException comEx) // Mohan: Exception due to Internet issue
{
SyncFailCount = SyncFailCount + 1;
Thread.Sleep(300);
}
catch (TimeoutException TimeoutEx) // Mohan: Exception due to timeout from web service
{
SyncFailCount = SyncFailCount + 1;
Thread.Sleep(300);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "CashPundit", MessageBoxButtons.OK, MessageBoxIcon.Error);
SyncFailCount = 0;
break;
}
// If there are more than 5 Sync Fails, break the loop and return false
if (SyncFailCount > 5)
{
SyncFailCount = 0;
break;
}
}
return IsSyncSuccess;
}
Trace what is happening when there is one CommunicationException or TimeoutException and the Thread.Sleep "fixes" this:
you are calling SyncCustomers from "outside" and setting the local variable IsSyncSuccess to false
you end up in a catch block and call SyncCustomers again.
this sets a new local variable IsSyncSuccess to false
the method succeeds and returns the true value
now you are back in the original version of your method, inside that catch block
you ignore the returned value, and the value of IsSyncSuccess local to this original invovation of your method is still false. This is the value that you are returning.
So a partial solution would be to not ignore the return value when you recursively call SyncCustomers from within a catch block:
IsSyncSuccess = SyncCustomers(...);
But then you still have a possible infinite recursion that you need to deal with:
When there is a CommunicationException or TimeoutException, you are increasing SyncFailCount, and calling SyncCustomers again - which resets that SyncFailCount back to 0! You are never reaching that limit of 5
I am not too sure which .net framework you are using but 4.0 and above i would recommned using Task method instead of thread This is sample only hope you can use this example
class Program
{
static void Main(string[] args)
{
Task<int> task = new Task<int>(Test);
task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
Console.ReadLine();
}
static int Test()
{
throw new Exception();
}
static void ExceptionHandler(Task<int> task)
{
var exception = task.Exception;
Console.WriteLine(exception);
}
}
add this line at the end of each catch Block
return IsSyncSuccess;
I have started to explore TPL in .NET to implement a windows service which will run multiple independent methods in parallel with some delay after each successful execution, following is a rough console application I came up with after looking at various examples:
class Program
{
static void Main(string[] args)
{
CancellationTokenSource _ct1 = new CancellationTokenSource();
CancellationTokenSource _ct2 = new CancellationTokenSource();
int count = 0;
var task1 = new Task(async () =>
{
try
{
while (true)
{
DoWork();
await Task.Delay(2000, _ct1.Token);
count++;
if (count >= 5)
{
throw new NotImplementedException();
}
}
}
catch (TaskCanceledException ex)
{
//Log cancellation and do not continue execution
Console.WriteLine("DoWork cancelled: " + ex.Message);
}
catch (Exception ex)
{
//Log error and continue with execution
Console.WriteLine("Error occurred at DoWork");
}
}, _ct1.Token, TaskCreationOptions.LongRunning);
var task2 = new Task(async () =>
{
try
{
while (true)
{
DoWork2();
await Task.Delay(2000, _ct2.Token);
count++;
if (count >= 5)
{
_ct2.Cancel();
}
}
}
catch (TaskCanceledException ex)
{
//Log cancellation and do not continue execution
Console.WriteLine("DoWork2 cancelled: " + ex.Message);
}
catch (Exception ex)
{
//Log error and continue with execution
Console.WriteLine("Error occurred at DoWork");
}
}, _ct2.Token, TaskCreationOptions.LongRunning);
task1.Start();
task2.Start();
Console.ReadKey();
}
public static void DoWork()
{
Console.WriteLine("Doing something...");
}
public static void DoWork2()
{
Console.WriteLine("Doing something else...");
}
}
In the above code when any exception occurs during the task execution, I need to log the error and then continue with the task execution, right now the task stops executing if there is an exception. My questions:
How to handle exceptions properly so that the task execution doesn't stop?
When I add a debugger break point at DoWork() method, the DoWork2() doesn't run which mean the tasks are not running in parallel on separate threads and running on a single thread and blocking each other. How to make sure the Tasks are running independent of each other on separate threads?
PS: The above code is a simple console app just to understand the workings of TPL, so please ignore if there are obvious design problems.
I believe that the simplest chage you can do to make your task1 running after exception is as follows:
var task1 = new Task(async () =>
{
while (true)
{
try
{
DoWork();
await Task.Delay(2000, _ct1.Token);
count++;
if (count >= 5)
{
throw new NotImplementedException();
}
}
catch (TaskCanceledException ex)
{
//Log cancellation and do not continue execution
Console.WriteLine("DoWork cancelled: " + ex.Message);
break;
}
catch (Exception ex)
{
//Log error and continue with execution
Console.WriteLine("Error occurred at DoWork");
count = 0; // without this you'll have exception thrown on each of further iterations
}
}
}, _ct1.Token, TaskCreationOptions.LongRunning);
Meaning that try...catch is moved inside the loop.
Please also note #pull420 comment on while you don't see task2 running
I want to log an error message in my application for a retry to call out the webservice but I only want to disply the error message once outside of the while loop instead of logging the error everytime it retries and fails or should I do a do while loop.
int retryCount = x;
int retryWait = y;
int retry = 0;
while (retry <= retryCount)
{
try
{
//get response
}
catch (InvalidOperationException invalid)
{
message = //display status message
}
catch (Exception exc)
{
//display log message
//retry again
retry++;
}
message = "Mamium tries have been exceeded
Logs.WriteError(message);
return false;
}
Simply reset the message, and check if there is one, so something like:
while (retry <= retryCount)
{
try
{
message = null;
//get response
}
catch (InvalidOperationException invalid)
{
message = invalid.Message; //display status message
}
catch (Exception exc)
{
//display log message
//retry again
message = exc.Message; //display status message
retry++;
}
if (!string.IsNullOrEmpty(message))
{
message = "Mamium tries have been exceeded"
Logs.WriteError(message);
return false;
}
}
You could use your retry and retryCount variables, for sample, and use finally block to increment anyway.
{ // main scope
int retry = 0, retryCount = 3;
string message = null;
while (retry < retryCount)
{
try
{
//get response
}
catch (Exception exc)
{
//any error, since you don't need to give another threatment for other erros, just use Exception
message = exc.Message;
}
finally
{
// increment retry anyway
retry++;
}
}
if (retry >= retryCount)
{
message = "Mamium tries have been exceeded"
Logs.WriteError(message);
return false;
}
return true;
}
If a finally block throws an exception, what exactly happens?
Specifically, what happens if the exception is thrown midway through a finally block. Do the rest of statements (after) in this block get invoked?
I am aware that exceptions will propagate upwards.
If a finally block throws an exception what exactly happens ?
That exception propagates out and up, and will (can) be handled at a higher level.
Your finally block will not be completed beyond the point where the exception is thrown.
If the finally block was executing during the handling of an earlier exception then that first exception is lost.
C# 4 Language Specification ยง 8.9.5: If the finally block throws another exception, processing of the current exception is terminated.
For questions like these I usually open up an empty console application project in Visual Studio and write a small sample program:
using System;
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("exception thrown from try block");
}
catch (Exception ex)
{
Console.WriteLine("Inner catch block handling {0}.", ex.Message);
throw;
}
finally
{
Console.WriteLine("Inner finally block");
throw new Exception("exception thrown from finally block");
Console.WriteLine("This line is never reached");
}
}
catch (Exception ex)
{
Console.WriteLine("Outer catch block handling {0}.", ex.Message);
}
finally
{
Console.WriteLine("Outer finally block");
}
}
}
When you run the program you will see the exact order in which catch and finally blocks are executed. Please note that code in the finally block after the exception is being thrown will not be executed (in fact, in this sample program Visual Studio will even warn you that it has detected unreachable code):
Inner catch block handling exception thrown from try block.
Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block
Additional Remark
As Michael Damatov pointed out, an exception from the try block will be "eaten" if you don't handle it in an (inner) catch block. In fact, in the example above the re-thrown exception does not appear in the outer catch block. To make that even more clear look at the following slightly modified sample:
using System;
class Program
{
static void Main(string[] args)
{
try
{
try
{
throw new Exception("exception thrown from try block");
}
finally
{
Console.WriteLine("Inner finally block");
throw new Exception("exception thrown from finally block");
Console.WriteLine("This line is never reached");
}
}
catch (Exception ex)
{
Console.WriteLine("Outer catch block handling {0}.", ex.Message);
}
finally
{
Console.WriteLine("Outer finally block");
}
}
}
As you can see from the output the inner exception is "lost" (i.e. ignored):
Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block
If there is an exception pending (when the try block has a finally but no catch), the new exception replaces that one.
If there is no exception pending, it works just as throwing an exception outside the finally block.
Quick (and rather obvious) snippet to save "original exception" (thrown in try block) and sacrifice "finally exception" (thrown in finally block), in case original one is more important for you:
try
{
throw new Exception("Original Exception");
}
finally
{
try
{
throw new Exception("Finally Exception");
}
catch
{ }
}
When code above is executed, "Original Exception" propagates up the call stack, and "Finally Exception" is lost.
The exception is propagated.
Throwing an exception while another exception is active will result in the first exception getting replaced by the second (later) exception.
Here is some code that illustrates what happens:
public static void Main(string[] args)
{
try
{
try
{
throw new Exception("first exception");
}
finally
{
//try
{
throw new Exception("second exception");
}
//catch (Exception)
{
//throw;
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
Run the code and you will see "second exception"
Uncomment the try and catch statements and you will see "first exception"
Also uncomment the throw; statement and you will see "second exception" again.
Some months ago i also faced something like this,
private void RaiseException(String errorMessage)
{
throw new Exception(errorMessage);
}
private void DoTaskForFinally()
{
RaiseException("Error for finally");
}
private void DoTaskForCatch()
{
RaiseException("Error for catch");
}
private void DoTaskForTry()
{
RaiseException("Error for try");
}
try
{
/*lacks the exception*/
DoTaskForTry();
}
catch (Exception exception)
{
/*lacks the exception*/
DoTaskForCatch();
}
finally
{
/*the result exception*/
DoTaskForFinally();
}
To solve such problem i made a utility class like
class ProcessHandler : Exception
{
private enum ProcessType
{
Try,
Catch,
Finally,
}
private Boolean _hasException;
private Boolean _hasTryException;
private Boolean _hasCatchException;
private Boolean _hasFinnallyException;
public Boolean HasException { get { return _hasException; } }
public Boolean HasTryException { get { return _hasTryException; } }
public Boolean HasCatchException { get { return _hasCatchException; } }
public Boolean HasFinnallyException { get { return _hasFinnallyException; } }
public Dictionary<String, Exception> Exceptions { get; private set; }
public readonly Action TryAction;
public readonly Action CatchAction;
public readonly Action FinallyAction;
public ProcessHandler(Action tryAction = null, Action catchAction = null, Action finallyAction = null)
{
TryAction = tryAction;
CatchAction = catchAction;
FinallyAction = finallyAction;
_hasException = false;
_hasTryException = false;
_hasCatchException = false;
_hasFinnallyException = false;
Exceptions = new Dictionary<string, Exception>();
}
private void Invoke(Action action, ref Boolean isError, ProcessType processType)
{
try
{
action.Invoke();
}
catch (Exception exception)
{
_hasException = true;
isError = true;
Exceptions.Add(processType.ToString(), exception);
}
}
private void InvokeTryAction()
{
if (TryAction == null)
{
return;
}
Invoke(TryAction, ref _hasTryException, ProcessType.Try);
}
private void InvokeCatchAction()
{
if (CatchAction == null)
{
return;
}
Invoke(TryAction, ref _hasCatchException, ProcessType.Catch);
}
private void InvokeFinallyAction()
{
if (FinallyAction == null)
{
return;
}
Invoke(TryAction, ref _hasFinnallyException, ProcessType.Finally);
}
public void InvokeActions()
{
InvokeTryAction();
if (HasTryException)
{
InvokeCatchAction();
}
InvokeFinallyAction();
if (HasException)
{
throw this;
}
}
}
And used like this
try
{
ProcessHandler handler = new ProcessHandler(DoTaskForTry, DoTaskForCatch, DoTaskForFinally);
handler.InvokeActions();
}
catch (Exception exception)
{
var processError = exception as ProcessHandler;
/*this exception contains all exceptions*/
throw new Exception("Error to Process Actions", exception);
}
but if you want to use paramaters and return types that's an other story
The exception propagates up, and should be handled at a higher level. If the exception is not handled at the higher level, the application crashes. The "finally" block execution stops at the point where the exception is thrown.
Irrespective of whether there is an exception or not "finally" block is guaranteed to execute.
If the "finally" block is being executed after an exception has occurred in the try block,
and if that exception is not handled
and if the finally block throws an exception
Then the original exception that occurred in the try block is lost.
public class Exception
{
public static void Main()
{
try
{
SomeMethod();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static void SomeMethod()
{
try
{
// This exception will be lost
throw new Exception("Exception in try block");
}
finally
{
throw new Exception("Exception in finally block");
}
}
}
Great article for Details
I had to do this for catching an error trying to close a stream that was never opened because of an exception.
errorMessage = string.Empty;
try
{
byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(xmlFileContent);
webRequest = WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "text/xml;charset=utf-8";
webRequest.ContentLength = requestBytes.Length;
//send the request
using (var sw = webRequest.GetRequestStream())
{
sw.Write(requestBytes, 0, requestBytes.Length);
}
//get the response
webResponse = webRequest.GetResponse();
using (var sr = new StreamReader(webResponse.GetResponseStream()))
{
returnVal = sr.ReadToEnd();
sr.Close();
}
}
catch (Exception ex)
{
errorMessage = ex.ToString();
}
finally
{
try
{
if (webRequest.GetRequestStream() != null)
webRequest.GetRequestStream().Close();
if (webResponse.GetResponseStream() != null)
webResponse.GetResponseStream().Close();
}
catch (Exception exw)
{
errorMessage = exw.ToString();
}
}
if the webRequest was created but a connection error happened during the
using (var sw = webRequest.GetRequestStream())
then the finally would catch an exception trying to close up connections it thought was open because the webRequest had been created.
If the finally didnt have a try-catch inside, this code would cause an unhandled exception while cleaning up the webRequest
if (webRequest.GetRequestStream() != null)
from there the code would exit without properly handling the error that happened and therefore causing issues for the calling method.
Hope this helps as an example
public void MyMethod()
{
try
{
}
catch{}
finally
{
CodeA
}
CodeB
}
The way the exceptions thrown by CodeA and CodeB are handled is the same.
An exception thrown in a finally block has nothing special, treat it as the exception throw by code B.
It throws an exception ;) You can catch that exception in some other catch clause.
Basically, what I want to do is pass a specific Exception to a more general Exception within the same try block. I've tried the following and it doesn't work:
static bool example(int count = 0)
{
try
{
work();
}
catch (TimeoutException e)
{
if (count < 3)
{
Console.WriteLine("Caught TimeoutException: {0}", e.Message);
return example(count + 1);
}
else
{
throw new Exception(e.Message);
}
}
catch (Exception e)
{
Console.WriteLine("Caught Exception: {0}", e.Message + " rethrown");
return false;
}
return true;
}
static void work()
{
throw new TimeoutException("test");
}
I want the TimeoutException to be only handled a certain amount of times before going to a more generic Exception. This is because the TimeoutException has additional information about the exception on a case by case basis. I do not want to duplicate the code for Exception under the else clause of TimeoutException. The reason I want all exceptions to be handled is that there may be other unknown exceptions that are thrown. The nature of the program requires it to not crash so I must account for any other exceptions and log them. How can I implement this?
You would need to nest this as 2 tries if you want to handle this this way:
static bool example(int count = 0)
{
try
{
try
{
work();
}
catch (TimeoutException e)
{
if (count < 3)
{
Console.WriteLine("Caught TimeoutException: {0}", e.Message);
return example(count + 1);
}
else
{
// Just throw, don't make a new exception
throw; // new Exception(e.Message);
}
}
}
catch (Exception e)
{
Console.WriteLine("Caught Exception: {0}", e.Message + " rethrown");
return false;
}
return true;
}
The "inner try/catch" will only catch TimeoutException, so any other exception will always go to the outer scope. When you rethrow, it'll automatically get caught by the outer scope, as well, which eliminates the need for killing the exception information. (If you throw new Exception, you lose your stack trace data, and other very valuable debugging information.)
Here's my take:
bool example()
{
// Attempt the operation a maximum of three times.
for (int i = 0; i < 3; i++)
{
try
{
work();
return true;
}
catch (Exception e)
{
Console.WriteLine("Caught exception {0}", e.Message);
// Fail immediately if this isn't a TimeoutException.
if (!(e is TimeoutException))
return false;
}
}
return false;
}
EDIT
If you want to actually do something with the TimeoutException, you could change the catch block like so:
catch (Exception e)
{
// As Reed pointed out, you can move this into the if block if you want
// different messages for the two cases.
Console.WriteLine("Caught exception {0}", e.Message);
TimeoutException timeoutException = e as TimeoutException;
if (timeoutException != null)
{
// Do stuff with timeout info...
}
else
{
// Not a timeout error, fail immediately
return false;
}
}