Description
Ben Rowlands opened SPR-5507 and commented
Spring provides a Lifecycle interface (Start & Stop) in addition to a mechanism to broadcast these signals to beans in the application context.
#8436 suggested an improvement to allow beans to define the order that these signals are delivered. The fix in 2.5.2 (following dependency order) is arguably a neater solution. One caveat with deriving the order from Spring (rather than allowing the components to declare their own order) is when Spring can't "see" the dependencies. For example, if some BPP "magic" detects components and installs them into other components Spring can't detect this dependency. It does appear this can (and should) be solved with the BPP registering the dependencies it is creating explicitly (via registerDependency() API).
A more subtle problem with the Lifecycle is what 'stop' means (for most use-cases 'start' rarely causes problems). Indeed, its not clear from the documentation when the stop method should return. The choices are:
A) Stop the component and returns when stopped; effectively joining on "end-stop" event
B) Request the component to stop but returns immediately, possibly before it has stopped
The DMLC interprets "stop" as (B). This can cause problems since other dependant components can receive the stop signal before the DMLC is fully stopped (and may still be processing messages). If a DMLC is using a message handler that itself makes use of a database pool then the following can occur:
- DMLC picks up a message from the queue
- DMLC stop signal delivered, no more messages are picked up but in-flight messages are finished
- Database pool stop signal delivered next (since DMLC depends on it via the message handler); DB pool is stopped
- Message handler requests a database connection and gets a exception since the pool is stopped
The problem defining "stop" as (A) is that large applications could take a long time shutdown. This can happen since components like the DMLC poll for work with a small timeout (in the order of 1 to 10 seconds). When the poll returns (and after any message is processed) the 'running' flag is checked to see if the thread should stop or carry on around the loop. Since the request for work can't be interrupted it can take up to the timeout interval for the thread to notice it should stop (assuming no work is available). To reduce load on our messaging queue manager we may run with a poll interval of say 10s. So each DMLC stop could take 10s and an application with 6 DMLCs could take 1 minute to shutdown.
To solve this phased shutdown could be introduced. For example, suppose we defined stop as:
/**
- Requests this component to stop, this method should
- not await completion of the stop, instead upon completion
- of the stop the provided callback should be run.
*/
public void stop(Runnable callback)
To shutdown the system all components with the same "phase" (defined by Ordered interface or otherwise) get the stop signal and we join on their completion. Once each phase is successfully stopped we continue to stop the next phase and so on. This approach allows us to concurrently shutdown phases whilst guaranteeing that components in earlier phases are already stopped. #9092 added such an API to the DMLC to allow for this.
It is possible to do this with our own PhasedLifecycle API and custom PhaseLifecycleProcessor (see attached files) however having this in Spring would help drive adoption of the Spring Lifecycle API and allow other components to participate in this model out the box (currently we have to wrap components manually).
Affects: 2.5.6
Attachments:
- PhasedLifecycle.zip (4.48 kB)
Issue Links:
- Documentation for SmartLifecycle and LifecycleProcessor [SPR-6341] #11007 Documentation for SmartLifecycle and LifecycleProcessor ("is depended on by")
- Add namespace support for "phase" on JMS listener-container [SPR-6460] #11126 Add namespace support for "phase" on JMS listener-container
Referenced from: commits 5e1c00c, 021663b, 5b088f5, b444220, 6ee17d2, 81efd48, 535ec5c, d5fd22c, a7c1f6b, a15a960
3 votes, 5 watchers