Exceptions thrown in Services no longer close connection after upgrade to 5.12

We recently upgraded from 5.9.2 to 5.12.0, and have noticed a change in behavior with how our Services are disposing of their database connections when a request has an uncaught exception.

This is in a .NET Framework 4.7.2 C# project utilizing .NET Standard 2.0 libraries.

Our endpoint processing in the Services roughly looks like this:

  [Route("/api/some_endpoint", "POST")]
  [DataContract]
  [Api(Description = "An endpoint.")]
  public class SomeDto { }

  public class ResponseDto { }

  public class SomeService : ServiceStack.Service
  {
    public ResponseDto Get(SomeDto requestDto)
    {
      using (var transaction = Db.OpenTransaction(IsolationLevel.ReadCommitted))
      {

        bool validationResult = ValidateRequest(Db, requestDto);
        if (!validationResult)
        {
          throw new ValidationException();
        }
        DoStuff(Db);
        transaction.Commit();
      }

      return new ResponseDto();
    }    
  }

where Db is provided by an OrmLiteConnectionFactory using the PostgreSqlDialect.Provider that has been registered in our AppHost.

Those validation exceptions are then handled in an exception handler we assigned to the Apphost “UncaughtExceptionHandler”, which translates them to a meaningful error we send back in our response.

After our upgrade, throwing this ValidationException no longer is now longer closing/disposing our connection used, which remains open until the Postgres database sees a timeout on it. Before the upgrade these connection would be dropped after we sent our response.

This was detected in our automated testing, where we might have hundreds of invalid requests sent quickly, which then would clog up our database, hitting its limit for maximum concurrent connections and causing subsequent connections to fail.

Is this a defect, or an intentional change in behavior? And do you have any preferred way we should be ensuring these connections are properly disposed, so that they do not hang around like this?

If necessary, I can likely send you a small project to replicate this if this is insufficient to demonstrate the issue.

Hi @trispott, I’m not aware of any related issues to DB disposal but I had a try to replicate the problem, unfortunately without any success, so I might be missing something.

If you could put together a minimal reproduction on GitHub I can help find the root cause.

Took a bit to find the time to get together a small solution to demonstrate this, but you can see it by running the two projects in the solution here, which are identical other than listening port and ServiceStack versions.

Although our observed issue above had to do with Db connections not being disposed, it was found that it was downstream of Services not being disposed as expected after an exception. This solution also shows our workaround to manually dispose services on exception we are using to mitigate this.

This is the image of the output from the two console apps, clearly showing Dispose not being called on the service after upgrade.

To test, I just hit the endpoints from a browser for simplicity.

Issue is because your Custom ServiceRunner takes over the default Exception Handling and instead of handling the exception (i.e. by converting it into a populated Error Response DTO) it throws it into an invalid state.

If you didn’t have a Custom Runner or it didn’t throw the Exception it would continue its normal behavior end the request properly.

The proper fix is to handle the Exception, i.e. convert it into your desired Error Response, but not throw it. You can call the base method with whatever Exception you’re trying to throw, if you’re trying to change the Exception the Service returns.

I’ve just added additional error handling to detect & log the invalid state and gracefully handle it.

Thanks. Our error handling here is somewhat clunky and could use some improvements, but we had failures from DB connections not being disposed after upgrade and just were trying to find out why.

1 Like