@Override
    public void deconstruct() {
        try {
            for (Reindexer reindexer : reindexers)
                reindexer.shutdown();

            executor.shutdown();

            executor.awaitTermination(5, TimeUnit.SECONDS); // Give it 5s to complete gracefully.

            curator.close(); // Close the underlying curator independently to force shutdown.

            if ( ! executor.isShutdown() && ! executor.awaitTermination(5, TimeUnit.SECONDS))
                log.log(WARNING, "Failed to shut down reindexing within timeout");
        }
        catch (InterruptedException e) {
            log.log(WARNING, "Interrupted while waiting for reindexing to shut down");
            Thread.currentThread().interrupt();
        }
        if ( ! executor.isShutdown()) {
            List<Runnable> remaining = executor.shutdownNow();
            log.log(WARNING, "Number of tasks remaining at hard shutdown: " + remaining.size());
        }

    }
Runs in all cluster controller containers, and progresses reindexing efforts.
Work is only done by one container at a time, by requiring a shared ZooKeeper lock to be held while visiting.
Whichever maintainer gets the lock holds it until all reindexing is done, or until shutdown.

@author jonmv
clustercontroller-reindexer/src/main/java/ai/vespa/reindexing/ReindexingMaintainer.java