-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add graceful shutdown #10701
base: 4.9.x
Are you sure you want to change the base?
Add graceful shutdown #10701
Conversation
This PR adds a new interface, GracefulShutdownLifecycle, that parts of the framework can implement to provide graceful shutdown functionality. It is designed to complement LifeCycle.stop(), though the implementations are unrelated. The netty HTTP server, on graceful shutdown, will stop accepting new connections, and wind down existing ones. HTTP/1 connections are closed as soon as in-progress requests have been served, while HTTP/2 and /3 connections send a GOAWAY packet to indicate to the client that no further requests will be processed. There is also a readiness health indicator that turns DOWN when a graceful shutdown begins. To keep the health endpoint accessible, there is a new `micronaut.server.netty.listeners.*.support-graceful-shutdown` config option to disable graceful shutdown for a management port. Graceful shutdown is triggered by application code through a new GracefulShutdownManager API. Graceful shutdown is best-effort. In-progress requests may take too long, or HTTP/2 clients may refuse to shut down their connection. For this reason, GracefulShutdownLifecycle returns a CompletionStage. The stage will complete when a graceful shutdown has been achieved, but this may be never, so a user should always add a timeout. After a graceful shutdown (or timeout), a normal LifeCycle.stop should be performed. Docs are still pending, I want Graeme to review the API before I write it up.
|
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownLifecycle.java
Outdated
Show resolved
Hide resolved
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownLifecycle.java
Outdated
Show resolved
Hide resolved
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownLifecycle.java
Outdated
Show resolved
Hide resolved
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownManager.java
Outdated
Show resolved
Hide resolved
...src/main/java/io/micronaut/http/server/netty/configuration/NettyHttpServerConfiguration.java
Show resolved
Hide resolved
.../src/main/java/io/micronaut/management/health/indicator/GracefulShutdownHealthIndicator.java
Outdated
Show resolved
Hide resolved
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownManager.java
Outdated
Show resolved
Hide resolved
.../src/main/java/io/micronaut/management/health/indicator/GracefulShutdownHealthIndicator.java
Outdated
Show resolved
Hide resolved
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownManager.java
Outdated
Show resolved
Hide resolved
Perhaps we should try and address #6493 in this PR as well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to include documentation about this new API in the main documentation.
@yawkat Hello! Wanted to see if there are any blockers around this issue since it's a quite important feature. |
No blockers, it's just on backburner |
Any news about this feature? |
@yawkat can you prioritise this next again after the client work |
# Conflicts: # context/build.gradle # http-server-netty/src/main/java/io/micronaut/http/server/netty/HttpPipelineBuilder.java # http-server-netty/src/main/java/io/micronaut/http/server/netty/NettyHttpServer.java # http-server-netty/src/main/java/io/micronaut/http/server/netty/handler/PipeliningServerHandler.java # management/src/test/groovy/io/micronaut/management/health/aggregator/HealthAggregatorSpec.groovy
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where is the logic that prevents new requests arriving and sends 503 back to the client except for management endpoints?
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownListener.java
Outdated
Show resolved
Hide resolved
@Singleton | ||
@Requires(bean = GracefulShutdownManager.class) | ||
@Requires(property = GracefulShutdownConfiguration.ENABLED, value = StringUtils.TRUE, defaultValue = StringUtils.FALSE) | ||
public final class GracefulShutdownListener implements ApplicationEventListener<ShutdownEvent> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make non-public and annotate with @Internal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept this public so people could Replace it in the bean context, not sure if that is a useful thing to do
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownManager.java
Outdated
Show resolved
Hide resolved
* @author Jonas Konrad | ||
*/ | ||
@Internal | ||
final class GracefulShutdownCapableScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor implements GracefulShutdownCapable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this only be a activated if graceful shutdown is enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far, all the GracefulShutdownCapable beans are enabled unconditionally. In fact, you can use GracefulShutdownManager without the config option. Only the ShutdownEvent listener is gated.
I think the overhead is negligible, and it allows for more flexibility for programmatic use for those that don't want to use the listener
@graemerocher The HTTP listeners stop the server socket so that no new connections are accepted, but existing connections are still served. I think this is better than still accepting connections but returning a status |
ok can you add docs? Thanks. |
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownCapable.java
Outdated
Show resolved
Hide resolved
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownCapable.java
Outdated
Show resolved
Hide resolved
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownManager.java
Outdated
Show resolved
Hide resolved
context/src/main/java/io/micronaut/runtime/server/GracefulShutdownListener.java
Outdated
Show resolved
Hide resolved
I'll do the docs tomorrow and then mark this as ready for review |
Not sure what's up with the build, sonar OOM? |
@@ -687,6 +697,18 @@ private static String displayAddress(NettyHttpServerConfiguration.NettyListenerC | |||
}; | |||
} | |||
|
|||
public static <T> CompletionStage<T> toCompletionStage(Future<T> future) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need to be public? Should it be moved to utility class? Seems odd it is here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a utility yes, but it's used in two packages so it has to be public. I wasn't sure where to put it, so I just put it here. The class is internal anyway.
This PR adds a new interface, GracefulShutdownLifecycle, that parts of the framework can implement to provide graceful shutdown functionality. It is designed to complement LifeCycle.stop(), though the implementations are unrelated.
The netty HTTP server, on graceful shutdown, will stop accepting new connections, and wind down existing ones. HTTP/1 connections are closed as soon as in-progress requests have been served, while HTTP/2 and /3 connections send a GOAWAY packet to indicate to the client that no further requests will be processed.
There is also a readiness health indicator that turns DOWN when a graceful shutdown begins. To keep the health endpoint accessible, there is a new
micronaut.server.netty.listeners.*.support-graceful-shutdown
config option to disable graceful shutdown for a management port.Graceful shutdown is triggered by application code through a new GracefulShutdownManager API.
Graceful shutdown is best-effort. In-progress requests may take too long, or HTTP/2 clients may refuse to shut down their connection. For this reason, GracefulShutdownLifecycle returns a CompletionStage. The stage will complete when a graceful shutdown has been achieved, but this may be never, so a user should always add a timeout. After a graceful shutdown (or timeout), a normal LifeCycle.stop should be performed.
Docs are still pending, I want Graeme to review the API before I write it up.