spring-projects / spring-data-geode

Spring Data support for Apache Geode
Apache License 2.0
51 stars 39 forks source link

Add lifecycle management to LocatorFactoryBean to control Locator start and stop [DATAGEODE-361] #408

Open spring-projects-issues opened 4 years ago

spring-projects-issues commented 4 years ago

John Blum opened DATAGEODE-361 and commented

Currently, when users declare the @LocatorApplication annotation on a Spring main class (e.g. a main class annotated with @SpringBootApplication), Spring will configure and bootstrap a Locator instance successfully, but then fall straight through, causing the JVM to exit (with exit code 0).

This improvement will couple the Locator instance start and stop operations with Spring's Lifecycle management capabilities using the Lifecycle, or alternatively the SmartLifecycle interface.

Technically, this means the LocatorLaucher.start() and LocatorLauncher.waitOnLocator() methods will be called in Lifecycle.start() and LocatorLauncher.stop() will be called in Lifecycle.stop(), while the (perceived) construction of the Locator object representing the distribution locator and location services will occur after initialization, as before.

Additional attributes will be added to the @LocatorApplication to control this behavior:


Affects: 2.4 M1 (2020.0.0), 2.2.9 (Moore SR9), 2.3.2 (Neumann SR2)

Reference URL: https://stackoverflow.com/questions/63197753/locatorapplication-starts-and-then-immediately-stops

spring-projects-issues commented 4 years ago

John Blum commented

Argh!

I am beginning to understand why I designed/built the LocatorFactoryBean class in SDG as I did.

Currently, the LocatorFactoryBean.afterPropertiesSet() method (technically, via the init() method) "starts" the Locator. This was necessary in order to get a reference to the Locator object, which may be injected into other Spring managed application components (i.e. beans), no matter how unlikely.

The LocatorLauncher class does not initialize a reference to a Locator object until the Locator is "started", as seen here. That is because, once again, Apache Geode's internal APIs (i.e. InternalLocator in this case) are 1) broken and 2) not open for extension.

Ideally, a Locator object could be fully constructed (i.e. created and initialized) and then "started" (when it is technically "safe" to do so) separately, as it should be! In that way, SDG's LocatorFactoryBean class could construct the Locator in afterProperties() (allowing a reference to the single Locator object to be passed and injected into other Spring managed application components, etc) and then "start" the Locator in Lifecycle.start(), at the appropriate moment.

spring-projects-issues commented 4 years ago

John Blum commented

UPDATE: I have altered the description, slightly!

I have decided to use the Proxy pattern to solve this problem.

Essentially, the problem stems from GemFire/Geode's APIs (and specifically the Locator API) since it does not cleanly separate the construction (creation & initialization) of a Locator from starting the Locator. These 2 concerns are naively combined into a single call, using (e.g.) a factory method. This hinders proper lifecycle management in different contexts, like the Spring container.

Unfortunately, the InternalLocator class (the GemFire/Geode provided implementation of Locator) and API 1) offers no relief (essentially has the same code smells as the abstract Locator class) and 2) is part of the "internal" API, making its use risky!

In order to preserve the same behavior as experienced by SDG users today from priorreleases experienced , the default behavior of LocatorFactoryBean will be to not wait on the Locator to stop. This means users must do 1 of 2 things:

1) Explicitly set the new waitOnLocator attribute when using the @LocatorApplication annotation, or... 2) Implement some means to cause the Locator based application to block, preventing the JVM from exiting. For example along with this.

This is pertinent since any means to "wait on the Locator" is subject to the vagaries of the OS Scheduler and platform Thread implementation, which can vary from platform to platform (particularly when using native Threads). Java's Project Loom should (eventually) help in this regard. Therefore, when the waitOnLocator attribute of the @LocatorApplication annotation is explicitly set, SDG will make a best effort to block the JVM from exiting. Again, there is no absolute guarantee.

By making this behavior optional rather than the default, it affords the developer the means to use the feature when required or implement their own approach (perhaps similar to the example above) as needed in a way that satisfies the application's requirements.