To be Reviewed By: 30 Oct 2020

Authors: Udo Kohlmeyer & Patrick Johnson

Status: Draft | Discussion | Active | Dropped | Superseded

Superseded by: N/A

Related: N/A

Problem

Whilst working on GEODE-8466 - Introduction of ClassLoaderService Abstraction, detailed in the Introduction of ClassLoaderService into Geode RFC, it quickly became apparent that it would be close to impossible to replace all previous static usages with an instance usage. This approach requires the ClassLoaderService instance to be passed in either as a method arg or as a constructor argument. In most cases, the effort to replace a single static method call with an instance method invocation would be 5-10x more work and would require the modification of many, directly or indirectly, related classes. In most cases, the replacement of the single static method invocation is more work than the apparent effort to pass it in.

In addition, the adding of extra arguments to constructor and method arguments, makes for an approach that is not only cumbersome but also unsustainable, as the addition of more argument to the constructors and methods requires exponentially growing the number of tests to ensure all cases are covered.

What would be nice is a DI (d-eye) framework (like Spring or Guice) that could be used to inject service instances into the classes as required. What this would mean is an extensive overhaul of the current design and service interfaces that would be too costly and take too long to introduce. A simple mechanism to lookup registered service instances would be most ideal, as this would reduce the number of changes to code, whilst removing static feature invocations and replacing them with single instance executable service calls.

Anti-Goals

The investigation of DI frameworks or the inclusion of DI frameworks into Geode is outside of this RFC.

Solution

A simple approach to register, lookup, and unregistering of Service instances is required. The simplest approach is to follow the Server-side service discovery pattern. Where there is a single registry and all services register themselves with the registry for simple lookup and usage. Unlike the described pattern, the ServiceRegistry is limited to in-JVM services only and no services outside of the JVM are currently supported.

This approach allows for the introduction of new services into Geode without having to explicitly wire them into all constructors and method invocations. Potentially breaking public APIs and backward compatibility.


ServiceRegistry


In the above class diagram, the ServiceRegistryInstance is a singleton only because it is simpler than adding an instance into the system and then having to wire it into all locations. This singleton ServiceRegistryInstance is only there until a real DI frame can be used and injection of services can be done in a safer and better manner than looking up services through the singleton.

Changes and Additions to Public Interfaces

N/A

Performance Impact

N/A

Backwards Compatibility and Upgrade Path

There will be no backward compatibility issues and no upgrade path additions are required.

Prior Art

Alternatives to this approach are:

  • Introduction of DI framework
  • Passing in Service instances into constructors and methods, possibly touching 100's of classes


By not taking this approach, the approach of passing service instances around via constructors and methods, increasing the classes touched and increasing the testing footprint that is required.

FAQ

Errata

  • No labels

4 Comments

  1. Is there a lifecycle associated with a Service?  How are services ordered within the registry?

    Something like:

    1. Start
    2. Invoke before start callback
    3. Start service 1
    4. Start service 2
    5. ...
    6. Invoke after start callback
    7. ...
    8. Stop
    9. Invoke before stop callback
    10. Stop service 2
    11. Stop service 1
    12. Invoke after stop callback
    1. There is no lifecycle within the ServiceRegistry.

      There is no intention to add a lifecycle to the ServiceRegistry, as this would complicate the scope and get closer to being a DI.

      This is merely a registry where services added to and looked up from. Services are keyed either by classname or using a custom name that is provided when added.

      Services can be looked up by type or name.

    2. Not sure what you mean by "how are services ordered". Services are keyed by a name and looked up by either name or type. It's a HashMap under the covers.

  2. This RFC has been dropped in favor of a single static singleton, which references a `ClassLoaderService`. This singleton is to replace the existing `ClassPathLoader`.

    Also dropped as it will be more preferable to have an RFC which introduces a DI framework, rather than a "placeholder".