Search code examples
c#simple-injector

Is it possible to set a timeout on Simple Injector


Is it possible to set a timeout on Simple Injector when creating an instance?

For example, I had a problem in the past when I instantiated an HTTPClient and the base URL was collected by a query in the database. And this HTTPClient was transient, so sometimes the database didn't respond as fast as we expected.

I know that it's a completely wrong approach and it was fixed. But it was the start of to search for this topic.

I spent a lot of time trying to find the root cause. So if I could set a timeout to Simple Injector to finish the installation it could throw an exception near the problem.


Solution

  • There's nothing built in to Simple Injector that allows you to 'flip a switch' and set a time out. Although Simple Injector is very flexible and a feature like this can be added by anyone, to me this is not something that you should let the DI Container manage. I even find it unlikely that there is any DI Container out there (and there are dozens) that does this for you OOTB.

    Instead, what you can do is change your registration to implement a timeout. This can be done using tasks, e.g.:

    container.Register<HTTPClient>(() =>
    {
        Task timeOutTask = Task.Delay(TimeSpan.FromSeconds(5));
        
        Task realTask = Task.Run(() =>
        {
            // Some possible long-running operation
        });
    
        Task completedTask = Task.WhenAny(timeOutTask, realTask).Result;
    
        bool hasTimedOut = completedTask != checkTask;
    
        if (hasTimedOut) throw new Exception("Time's up");
        return ...;
    });
    

    WARNING: I'm no expect in this part of the .NET API, so it could be that the implementation above, of how to cancel a task, is not full proof. You should Google, check Stephen Cleary's blog post and ask here on SO to make sure you got the correct implementation. The code above is merely given as an example of how you could solve this issue.

    You already mentioned that you know this is a bad idea, but I really would like to stress that it really is. For anyone who might be reading this in a few years time. Object composition must be fast and reliable. This means that connecting to a database while resolving is a bad idea. Such call should be moved out of the construction phase done after. This can be done in a lazy fashion, e.g. when the service is used for the first time, or directly after startup. What ever you do, keep I/O out of the phase where you compose your object graphs (when you call GetInstance or Resolve).