Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency injection in long-running Windows service - Composition root the right idea?

I am writing a Windows Service that (if all goes according to plan) will run for months at a time. Throughout the lifetime of the service, it will maintain several WCF services (named pipes for communicating with other local apps), it will run an embedded data store (RavenDB probably, which is more or less irrelevant to this question), and it will use some third-party software to maintain a SIP service (VoIP functionality). Some of the challenges I am facing means having to react to events and create some new business objects to handle what these events represent.

Now, I've read Mark Seemann's book (at least the relevant parts for this discussion), and I understand why a service locator is bad, and why handling this in the composition root (service starting point in my case) is good - in the general case.

However, what I don't understand is how this can apply to every situation. I see how it would be perfect in the cases where you CAN compose your whole root at the start of the application, or in something like MVC where the IoC engine is used per request by the framework. However, for a long-running service, I imagine it would be inefficient in the best case, and impossible in some cases, to create all objects up front. I can't imagine being able to write a non-trivial service that gets all the objects it could ever need up front, and never need to create new ones as life goes on.

Now, this isn't enough to lure me to the dark side and take on the expense of hidden dependencies like a service locator would have me do. But what is the right thing to do here? If I have a CallHandlerService that needs to be created in response to each incoming call (because it uses expensive, unmanaged resources for instance), how do I go about doing that?

Composition root + just a wee bit of service locator?

That last part wasn't serious, but I would still love to know how to solve this properly.

like image 533
Rune Jacobsen Avatar asked May 18 '13 15:05

Rune Jacobsen


1 Answers

It is possible to break the question into two:

  • How to manage scope
    • Avoid creation of all possible dependencies up-front
    • Create only required dependencies
  • How to manage lifetime
    • Keep references to already created dependencies
    • Reuse dependencies if it is possible
    • Cleanup them as soon as possible

How to manage scope

You could define either interfaces or realizations of several specialized Abstract Factories, each of them will limited to manage only its own special sort of dependencies. For example: one for database related dependencies, another SIP related. Then you could inject factories themselves, not dependencies, and retrieve dependencies from them.

Isn't it sound like Service Locator? Yes it is, but it is not Service Locator. You could read more on this at Mark Seemann blog: Abstract Factory or Service Locator?.

And if Abstract Factories are ok, take a look at Ninject.Extensions.Factory to create them automatically based upon your IKernel configuration

How to manage lifetime

If you are going to run your service 24-7, this is more complex and important part. Here I could give you only several practical advises:

  • For such kind of services, failures at external dependency side (i.e. database, services) are routine, not an exception
  • Do not keep any references to dependencies yourself in code aiming for performance or reuse
  • Do not use complex lifetimes (for example named scope for Ninject )
  • Do release dependencies as soon as possible. Configure Ninject to manage them for you.
  • Think about timeouts for dependencies, to recreate new instances
  • May be for long-running tasks, create separate instance of Kernel, and make sure that you have disposed them afterwards
like image 183
Akim Avatar answered Oct 15 '22 02:10

Akim