Hi Don,Internally there have been a few discussions about how to manage inter-service dependencies during startup (and to a lesser extent during shutdown). This turns out to be a difficult problem from an API perspective and especially from an implementation perspective.Also, I think there are a few problem with your proposed API.1. using a List<Service> to express dependencies would IMHO introduce unnecessary serialization of service startup. Service dependencies in my experience are not linear but rather a forest of small 1 level trees. (i.e. there is often a base service and a number of other services that are dependent upon it). If we wanted to support an explicit dependency management api then i think we would need to model them as a possibly unconnected DAG.2. Modeling a collection of Services as a Single service turns out to be fraught with issues. Internally, the original version of ServiceManager used this approach and it made dealing with service failure very difficult which is why ServiceManager very explicitly does not implement Service (e.g. think about how you would implement the state() method in the wrapper service, what if one service spontaneously failed or stopped itself?).3. Even if you came up with a workable API for managing inter-service dependencies during startup you still have the same issue when dealing with dependencies between service and non-service code which this solution doesn't actually address. (e.g. consider a Servlet that is accessing a service during its init() method, or during its service() method? how do you ensure that the Servlet isn't initialized by the container until its Service based dependencies have started).I have a proposed solution to this problem but there isn't consensus that it is a good idea yet (caveat emptor) and it is certainly not a complete solutions, but in my relatively simple use cases it works well and i suspect it would for you as well.If you have a service with public methods that depend on the service being started to function then implement this method in your serviceprivate void ensureStarted() {startAndWait(); // This ensures that we have startedif (!isRunning()) {logger.severe("Service is " + state());}}and call ensureStarted() at the beginning of every public method that depends on the service being started. This pattern means that the inter-service dependencies will be discovered lazily at runtime and it also deals well with dependencies between service and non-service code. There are some issues with it though.1. It does nothing to cope with correctly ordering service shutdown. (In my experience, very few Services do anything in their shutdown methods and i have yet to see one that needed to wait for another service to stop before it could stop, so at worst this would be a rare issue).2. It requires Services to have reasonable behavior once they have FAILED or STOPPED. (or alternatively you can just throw IllegalStateExceptions if it is not RUNNING).3. If you have a circular dependency between services it will deadlock. (IMHO, this is not so bad, since such a dependency is a programmer error but it is unfortunate that the failure condition is deadlock and not something more reasonable like an exception being thrown).4. It turns a lot of methods into potentially blocking methods which can be unexpected.Another option is just to manage the startup yourself. One of the nice features of ServiceManager is that all its features work correctly even if someone else starts or stops the services. So if you know your dependencies you could implement this feature without any changes to ServiceManager itself. e.g.ServiceManager manager= new ServiceManager(ImmutableList.of(baseService, dependentService1, dependentService2));baseService.startAndWait();dependentService1.start();dependentService2.start();dependentService1.startAndWait();dependentService2.startAndWait();// then when you want to stop everything do:dependentService1.stop();dependentService2.stop();dependentService1.stopAndWait();dependentService2.stopAndWait();baseService.stopAndWait();
That code would ensure that things are started and stopped in the correct order. (But it does not handle services which might fail or stop themselves).LukeP.S. I don't have a proof, but i don't actually think it is possible to solve the service dependency issue externally to the services. i.e. if one service has a dependency on another it will probably require a change to the implementation of at least one of the services (and possibly) both to implement both proper startup and shutdown ordering. So a real solution to this issue may require changes to the service interface / AbstractService.
--
guava-...@googlegroups.com
Project site: http://guava-libraries.googlecode.com
This group: http://groups.google.com/group/guava-discuss
This list is for general discussion.
To report an issue: http://code.google.com/p/guava-libraries/issues/entry
To get help: http://stackoverflow.com/questions/ask (use the tag "guava")