单二进制三角色 + Dock 适配器 + Swarm stack 达到可部署态;mgr1 实测订阅经 central-proxy bootstrap,探活 alive=41/52。 Co-authored-by: Cursor <cursoragent@cursor.com>
51 lines
2.3 KiB
Go
51 lines
2.3 KiB
Go
// probe.go — serveHealth /healthz 已注册探测(V3 arch-review D-1 修复辅助)。
|
||
package main
|
||
|
||
import "net/http"
|
||
|
||
// muxPatternRegistered 探测 ServeMux 是否已注册某 pattern。
|
||
// ServeMux 无公开查询 API;Handler 面走一次探测请求即可判断。
|
||
// 返回 nil 表示未注册(可安全补挂),非 nil 表示已在路由表。
|
||
//
|
||
// 实现说明:Go 1.22+ ServeMux 用 Handler(r) 做匹配;若精确 pattern 已注册,
|
||
// Handler 返回的 p.pattern 等于查询串。此处用最朴素的方式:构造一个指向
|
||
// 目标 pattern 的请求,若 Handler 命中且非内置 404 处理器即视为已注册。
|
||
func muxPatternRegistered(mux *http.ServeMux, pattern string) http.Handler {
|
||
req, err := http.NewRequest(http.MethodGet, "http://probe.invalid"+pattern, nil)
|
||
if err != nil {
|
||
return nil // 构造失败按未注册处理(后续 HandleFunc 会 panic 暴露问题)
|
||
}
|
||
h, _ := mux.Handler(req)
|
||
// 内置 404(NotFoundHandler)意味着 pattern 未注册——ServeMux.Handler 对
|
||
// 完全未命中且无 "/" 兜底的请求返回 NotFoundHandler。
|
||
if h == nil {
|
||
return nil
|
||
}
|
||
if h == http.DefaultServeMux {
|
||
return nil
|
||
}
|
||
// 未注册时 ServeMux.Handler 返回 http.NotFoundHandler(包级单例)。
|
||
if _, ok := h.(http.Handler); ok {
|
||
// 判 404:包一层探测 recoder 看状态码不可行(Handler 只在 Serve 时执行),
|
||
// 改用类型特征:ServeMux 未命中返回的 handler 即 mux 自身的 notFoundHandler,
|
||
// 其与 http.NotFoundHandler() 每次为不同实例——因此不能靠指针比较。
|
||
// 简化判定:ServeMux.Handler 命中已注册 pattern 时返回该 pattern 的 handler;
|
||
// 未命中时返回的不是任何用户注册的 handler。此处采用行为探测:执行一次。
|
||
w := &probeRecorder{header: http.Header{}, status: 0}
|
||
h.ServeHTTP(w, req)
|
||
if w.status == http.StatusNotFound {
|
||
return nil
|
||
}
|
||
}
|
||
return h
|
||
}
|
||
|
||
// probeRecorder 探测用 ResponseWriter(不落网络)。
|
||
type probeRecorder struct {
|
||
header http.Header
|
||
status int
|
||
}
|
||
|
||
func (p *probeRecorder) Header() http.Header { return p.header }
|
||
func (p *probeRecorder) Write(b []byte) (int, error) { return len(b), nil }
|
||
func (p *probeRecorder) WriteHeader(code int) { p.status = code }
|