We have a lot of cleanup methods that do not account for the possibility of failure.
For instance, in {{IndexManagerHolder.stop()}}:
{code} public synchronized void stop() { for ( IndexManager indexManager : getIndexManagers() ) { indexManager.destroy(); } // ... more code ... } {code}
If the first index manager fails to stop, then none of the following index managers will be stopped. But theoretically, they could be completely different implementations, and thus the second index manager may stop perfectly well even if the first one failed.
There are many places making a similar mistake, most notably:
* IndexManagerHolder.stop * Most implementations of Stoppable.stop * Most implementations of IndexManager.destroy * ImmutableSearchFactory.close * SearchIntegratorBuilder.cleanupFactoryState (soon to be merged as part of HSEARCH-2277)
We may want to implement "composite cleanups" in a more reliable way, for instance with a utility object similar to Guava's {{Closer}} (see [here|https://github.com/google/guava/wiki/ClosingResourcesExplained#closer)]). Note this class is very simple, we don't need Guava, we can just re-implement it ourselves.
Usage examples for this "Closer": ``` public void close() throws Exception { Closer closer = new Closer(); closer.add( entityManager ); // Specific method, entityManager does not implement Autocloseable. Maybe rather something like add( entityManager::close )? closer.add( scrollableResults ); // Autocloseable closer.add( statelessSession ); // Autocloseable closer.close(); // Closes everything, uses addSuppressed if necessary, throws an Exception } ```
try (Closer closer = new Closer()) { // ...
EntityManager em = emf.createEntityManager(); closer.add( em );
// ... } |
|