Using Try-Catch-Finally to process code for API endpoint – What are the drawbacks?

I know this is bad design and I am trying to find any reason to not do this, so I need some help.

I have an API endpoint that is being hit and needs to respond back with an OK response within a few seconds at most. Currently we are taking the call and processing a lot of data and then returning the OK, however, if the DoLotsOfWork method times out, no OK response is being returned.

public IActionResult DoWork([FromBody] MyDTO myDto){
     DoLotsOfWork();
    return OK()
}

Now I’ve suggested that we migrate over to some sort of Queue and make the job run there but I am being told no as that work would take to long. Instead I am being told to do this.

public IActionResult DoWork([FromBody] MyDTO myDto){
   try{
       return OK();
   }
   catch{
   }
   finally{
      DoLotsOfWork();
   }  
}

Does anyone know of any drawbacks by doing things this way?

  • You might get downvoted here. Perhaps softwareengineering.stackexchange.com is a better spot to ask? The second piece of code isn’t a good selection. It will just return “OK” and disregard anything that happens in “DoLotsOfWork”. Nothing will be returned to the consumer

    – 




  • 1

    The second code block seems wrong to me. Why would you want to return OK(); in a scenario where you could get an error?

    – 




  • There’s no sense in catch here since OK() doesn’t throw any exception

    – 




  • Why would you do lot of work after you return ? The idea behind try block is to finish your actual work and if it breaks catch it and the purpose of final block is to execute in both the cases of try / catch block which is generally to dispose of objects etc.

    – 




  • 1

    The second snippet appears to be a convoluted way to write IActionResult retval = OK(); DoLotsOfWork(); return retval; This simpler version still has some drawbacks, but abusing try/finally isn’t one of them.

    – 




Since the actual question appears to be entirely “What are the drawbacks?”, and you appear to know how the try-catch-finally is working as hacky a way to execute code after the API responds (despite some people in the comments and answers explaining what it does), I’ll just link to this very well-written StackOverflow answer to a similar question authored by Stephen Cleary.

Edit 2: vatbub’s answer below listing issues with that approach makes a good point in #4 (1-3 mostly reiterate try-catch misuse), and the description that follows elaborates.

Edit: In case it disappears from the internet:

And I need to “fire and forget”

I have a blog post that goes into details of several different
approaches for fire-and-forget on ASP.NET.

In summary: first, try not to do fire-and-forget at all. It’s almost
always a bad idea. Do you really want to “forget”? As in, not care
whether it completes successfully or not? Ignore any errors? Accept
occasional “lost work” without any log notifications? Almost always,
the answer is no, fire-and-forget is not the appropriate approach.

A reliable solution is to build a proper distributed architecture.
That is, construct a message that represents the work to be done and
queue that message to a reliable queue (e.g., Azure Queue, MSMQ, etc).
Then have an independent backend that process that queue (e.g., Azure
WebJob, Win32 service, etc).

Should I just call Task.Run() without any async-await?

No. This is the worst possible solution. If you must do
fire-and-forget, and you’re not willing to build a distributed
architecture, then consider Hangfire. If that doesn’t work for you,
then at the very least you should register your cowboy background work
with the ASP.NET runtime via
HostingEnvironment.QueueBackgroundWorkItem or my ASP.NET Background
Tasks library
. Note that QBWI and AspNetBackgroundTasks are both
unreliable solutions; they just minimize the chance that you’ll lose
work, not prevent it.

There’s two problems with your approach:

  1. That would only work with end points that don’t return anything. How can you return something before you build the object to return?

  2. The try block is, presumably, to “handle” (spoiler alert, you’re not handling anything) exceptions in your code, right? Well, it’s not the Ok() call that can throw, it’s your code, the one in finally. Unless you also put that in a try, any exceptions in it will still be unhandled, thus defeating the only possible reason I see to write code like that in the first place.

Your design is flawed for multiple reasons, from least to most important:

  1. This is not the intended use for try-catch-finally and fellow developers in your team will look at this and will have trouble understanding what’s going on.
  2. Bad API design: As pointed out by other answers, you are lying to the client that everything is OK, even though you have no idea yet if that’s the case.
  3. Missing error handling: If DoLotsOfWork()throws an exception, you will either not get notified or worse, your entire server process may crash, because the exception is not caught.
  4. Most importantly, your thread will still block until DoLotsOfWork() is done, making your application susceptible for denial-of-service attacks.

To solve your issues, you need to change your API design. By returning OK, you are obviously lying to the client. In a perfect world, you would have an API-endpoint where the client can submit the data to process, and you would return something along the lines of “Your data was successfully scheduled for processing”. You would then have another endpoint where the client could check the progress of the processing.

Changing your API design in this way, however, does take a lot of time, which is probably why your boss is hesitant to do this.

However, if you neglect the fact that you are lying to your client, and still return OK and offer no additional API endpoint for progress checking, you can still either have a separate processing thread that queues up all the data or just spawn a new thread in place for each processing job. The effort to implement such a solution is pretty much the same as for implementing the hacky try-catch-finally solution, but it still saves you from the possibility of being DDOSed.

Okay, so the major problem is:

You are going to tell whomever sent the API call, that the response was okay.
And if “DoLotsOfWork” times out, or throws any kind of exception, that little nugget of boom, will actually force a restart of the API or shut it down, depending on how it is deployed.

Leave a Comment