Terminator is a small Java library that coordinates the orderly shutdown of heterogeneous services. It understands two kinds of services:
- Blocking services (
BlockingTerminable) that finish all work before returning fromterminate(). - Non-blocking services (
NonBlockingTerminable) that initiate shutdown in the background and exposeawaitTermination(Duration)to finish up.
The coordinator makes sure non-blocking services are signalled first and waited on, while blocking services are stopped afterwards in reverse registration order. It also keeps you honest about interrupts and timeout handling so shutdown code stays responsive.
- Register any number of blocking or non-blocking services using distinct marker interfaces.
- Initiate shutdown once with
Terminator#terminate(), or call it repeatedly without side effects. - Wait for the async tail of shutdown to finish with
awaitTermination(Duration); negative durations are treated as zero, and a zero wait is still passed through to the services. - Aggregates failures thrown during termination, keeping the first as the cause and suppressing the rest.
- Propagates interrupts consistently during both
terminate()andawaitTermination().
Add the dependency to your Gradle build:
dependencies {
implementation 'io.github.leanish:terminator:0.1.0'
}class HttpServer implements BlockingTerminable {
private final Server server;
...
@Override
public void terminate()
throws InterruptedException {
server.stop(); // blocks until fully stopped
}
}
class QueueProcessor implements NonBlockingTerminable {
private final ExecutorService executor;
...
@Override
public void terminate() {
executor.shutdown(); // starts shutdown but returns immediately
}
@Override
public boolean awaitTermination(Duration timeout)
throws InterruptedException {
return executor.awaitTermination(timeout.toNanos(), TimeUnit.NANOSECONDS);
}
}Terminator terminator = new Terminator();
terminator.register(httpServer);
terminator.register(queueProcessor);
...
terminator.terminate();
boolean finished = terminator.awaitTermination(Duration.ofSeconds(5));
if (!finished) {
// log or trigger fallback action
}This project uses Gradle 8 and Java 21:
./gradlew build # compile, test, package
./gradlew test # run the test suiteTo regenerate the API documentation:
./gradlew javadocSee CHANGELOG.md for notable updates.
Issues and pull requests are welcome. Please run ./gradlew test locally before submitting changes.
This project is distributed under the terms of the MIT License.