Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I ensure an operation won't crash the whole app?

I have an application performing some additional jobs like cleaning old logs, sending notifications and so on. If one job fails I don't want the whole application to stop working and not perform jobs what left.

So for example,

await SendUsersBirthdayEmailsAsync(); // <-- if something fails while trying to send birthday emails here, I don't want the app to stop working and not clean logs and so on...
await DeleteOutdatedLogsAsync();
await SendSystemNotificationsAsync();

What would you recommend me to go with?

like image 523
kseen Avatar asked Jan 26 '23 22:01

kseen


1 Answers

Use try-catch block on every part of the code that can fail.
Depending on what you need, use try-catch-finally block.

On every catch block, log the exception however you want. I use Nlog for logging so i suggest looking into that.

try{
    //do work here
}
catch(Exception e){
    //log exception here
}
//optional
finally{
    //do optional needed work here
}

Something like this:

public bool SendUsersBirthdayEmailsAsync(){
    try{
        SendMail();
    }
    catch(Exception e){
        LogException(e);
    }
    //optional
    finally{
        OptionalWork();
    }       
}

EDIT: About avoiding using generic exception

You can always use multiple catch blocks any define different behavior for each type of exception. This is useful when you know what kind of exception can be expected.
Example:

public bool SendUsersBirthdayEmailsAsync(){
    try{
        SendMail();
    }
    catch (ThreadAbortException tae)
    {
        LogException(tae);
        //do something specific
    }
    catch (ThreadInterruptedException tie)
    {
        LogException(tie);
        //do something specific
    }
    catch(Exception e){
        LogException(e);
    }
    //optional
    finally{
        OptionalWork();
    }       
}

EDIT 2: Official Microsoft guidance for exception handling.

Use try/catch blocks around code that can potentially generate an exception and your code can recover from that exception. In catch blocks, always order exceptions from the most derived to the least derived. All exceptions derive from Exception. More derived exceptions are not handled by a catch clause that is preceded by a catch clause for a base exception class. When your code cannot recover from an exception, don't catch that exception. Enable methods further up the call stack to recover if possible.

Clean up resources allocated with either using statements, or finally blocks. Prefer using statements to automatically clean up resources when exceptions are thrown. Use finally blocks to clean up resources that don't implement IDisposable. Code in a finally clause is almost always executed even when exceptions are thrown.

like image 169
Matt Avatar answered Jan 28 '23 17:01

Matt