Compare commits

...
Author SHA1 Message Date
zhangwenjian d6309c75be docs📝: state what the draining answer is worth
Three comments said readiness failing before the server stops accepting gives
a load balancer the chance to withdraw the instance before its connections are
cut. Nothing between the two lines makes that possible: BeginDraining is
immediately followed by the shutdown, and a poller on a multi-second interval
never observes the flip.

On Kubernetes the endpoint is withdrawn when the Pod receives a
deletionTimestamp, concurrently with SIGTERM and independent of what the probe
returns, so the probe result is not the mechanism there either.

The order itself stands - reporting the state after the connections are cut is
worse - so the comments now say the order is necessary and not sufficient, and
that a window needs a configured delay that does not exist yet.
2026-09-06 19:04:42 +08:00
3 changed files with 21 additions and 9 deletions
+3 -3
View File
@@ -38,9 +38,9 @@ func registerMonitorRouter(v1 *gin.RouterGroup) {
// 就绪检查
//
// The answer to "should I send you requests". It fails while a dependency
// is unreachable, and from the moment shutdown begins - which is before
// the server stops accepting, so a load balancer can take this instance
// out of the pool while it can still finish what it has.
// is unreachable, and from the moment shutdown begins. Nothing waits on
// that second answer today, so it is readable rather than actionable -
// the package comment in common/health says what it would take.
v1.GET("/ready", func(c *gin.Context) {
if health.Draining() {
c.JSON(http.StatusServiceUnavailable, gin.H{
+4 -4
View File
@@ -219,10 +219,10 @@ func run() error {
// that has already run.
sdk.Runtime.BeginShutdown()
// Readiness fails from here, which is before the server stops accepting.
// The order is the whole point: a load balancer that is told "not ready"
// while this instance can still finish what it has in flight takes it out
// of the pool without dropping anything. Reversed, the connections are cut
// first and the health check reports it afterwards.
// That order is necessary and not sufficient: reversed, the state is
// reported after the connections are already cut, but as written there is
// nothing between the two lines for a balancer to observe. See the package
// comment in common/health.
health.BeginDraining()
log.Info("Shutdown Server ... ")
+14 -2
View File
@@ -11,8 +11,20 @@
// - /ready is readiness: should this instance receive requests now. It fails
// while the dependencies are unreachable, and - the part that only exists
// because of the life-cycle phases - it fails as soon as shutdown begins,
// before the server stops accepting, so a load balancer has a chance to
// take the instance out before connections are cut.
// before the server stops accepting.
//
// # What the draining answer is worth today
//
// It is an answer that can be read, not one a balancer acts on. Nothing waits
// between the flip and the shutdown, and a poller on a multi-second interval
// never observes it. On Kubernetes the endpoint is withdrawn when the Pod
// receives a deletionTimestamp, concurrently with SIGTERM and whatever the
// probe returns; the probe result is not what removes it.
//
// Answering before the server stops accepting is still the right order - the
// reverse reports the state after the connections are already cut - but order
// alone does not produce a window. That needs a configured delay between the
// two, which this process does not have.
package health
import (