feat: drain readiness before graceful shutdown
This commit is contained in:
@@ -4,7 +4,9 @@ package httpserver
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"git.yuntuo.hk/k2safe/orbit/internal/buildinfo"
|
||||
@@ -14,6 +16,37 @@ import (
|
||||
|
||||
type Checker func(context.Context) error
|
||||
|
||||
// Readiness 将数据库/结构检查与进程排空状态合并为一个就绪门控。
|
||||
// 收到终止信号后先调用 BeginDrain,再停止接收新请求;存量请求仍由
|
||||
// http.Server.Shutdown 在限定时间内完成。这样编排平台有机会先看到 503。
|
||||
type Readiness struct {
|
||||
checker Checker
|
||||
draining atomic.Bool
|
||||
}
|
||||
|
||||
// NewReadiness 创建可在优雅下线期间切换为未就绪的门控。
|
||||
func NewReadiness(checker Checker) *Readiness {
|
||||
return &Readiness{checker: checker}
|
||||
}
|
||||
|
||||
// Check 执行就绪检查;排空开始后始终返回内部错误,由 HTTP 层统一隐藏细节。
|
||||
func (r *Readiness) Check(ctx context.Context) error {
|
||||
if r == nil || r.draining.Load() {
|
||||
return errors.New("server is draining")
|
||||
}
|
||||
if r.checker == nil {
|
||||
return errors.New("readiness checker is unavailable")
|
||||
}
|
||||
return r.checker(ctx)
|
||||
}
|
||||
|
||||
// BeginDrain 先于 http.Server.Shutdown 调用,阻止排空窗口内的新流量。
|
||||
func (r *Readiness) BeginDrain() {
|
||||
if r != nil {
|
||||
r.draining.Store(true)
|
||||
}
|
||||
}
|
||||
|
||||
func New(addr string, ready Checker, tasks ...*service.Service) *http.Server {
|
||||
mux := http.NewServeMux()
|
||||
write := func(w http.ResponseWriter, status int, body map[string]string) {
|
||||
|
||||
Reference in New Issue
Block a user