fix(repo):统一发布健康与只读质量门禁
bat-rust / Build and test Rust (push) Canceled after 0s
bat-rust / Build and test Go API (push) Canceled after 0s

This commit is contained in:
2026-09-13 22:09:44 +08:00
parent 32fc64fa83
commit c17904ee1c
25 changed files with 869 additions and 184 deletions
+45 -10
View File
@@ -3,6 +3,7 @@ package api
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
@@ -18,9 +19,10 @@ type Server struct {
logger *log.Logger
limiter *tokenBucketLimiter
mu sync.RWMutex
idx *ReleaseIndex
meta DiscoverResult
refreshMu sync.Mutex
mu sync.RWMutex
idx *ReleaseIndex
meta DiscoverResult
refreshInProgress bool
lastRefreshStart time.Time
@@ -95,10 +97,46 @@ func (s *Server) Handler() http.Handler {
// Refresh rebuilds the release index via RPC (and optional resource-root override).
func (s *Server) Refresh(ctx context.Context) error {
// Serialize refreshes so an older, slower RPC response cannot replace a
// newer snapshot and so refresh diagnostics describe one attempt at a time.
s.refreshMu.Lock()
defer s.refreshMu.Unlock()
started := s.beginRefresh()
result, err := DiscoverAndIndex(ctx, s.backend, s.cfg.ResourceRoot)
if err != nil {
s.finishRefresh(started, err, nil)
s.mu.Lock()
warnings := []string(nil)
if result != nil {
s.meta = *result
warnings = append(warnings, result.Warnings...)
} else {
s.meta = DiscoverResult{}
}
warnings = append(warnings, fmt.Sprintf("refresh: %v", err))
s.idx = &ReleaseIndex{
Source: "empty",
Distribution: unavailableRustDistributionHealth(),
byRel: map[string]int{},
}
s.meta.Index = s.idx
s.meta.ResourceRoot = ""
s.meta.Distribution = s.idx.Distribution
s.finishRefreshLocked(started, err, warnings)
s.mu.Unlock()
return err
}
if result == nil || result.Index == nil {
err := fmt.Errorf("refresh returned no release index")
s.mu.Lock()
s.idx = &ReleaseIndex{
Source: "empty",
Distribution: unavailableRustDistributionHealth(),
byRel: map[string]int{},
}
s.meta = DiscoverResult{Index: s.idx, Distribution: s.idx.Distribution}
s.finishRefreshLocked(started, err, []string{err.Error()})
s.mu.Unlock()
return err
}
s.mu.Lock()
@@ -229,6 +267,7 @@ func (s *Server) handleBootstrap(w http.ResponseWriter, r *http.Request) {
Release: sum.Snapshot,
ResourceRoot: sum.ResourceRoot,
Source: sum.Source,
Distribution: sum.Distribution,
ManifestVersion: sum.ManifestVersion,
EntryCount: sum.EntryCount,
PresentCount: sum.PresentCount,
@@ -287,6 +326,7 @@ func (s *Server) handleHealthz(w http.ResponseWriter, r *http.Request) {
"missing_count": sum.MissingCount,
"source": sum.Source,
"warnings": meta.Warnings,
"distribution": sum.Distribution,
// Database/redis are reserved config surface for a normal API process.
"database_configured": s.cfg.DatabaseURL != "",
"redis_configured": s.cfg.RedisURL != "",
@@ -316,6 +356,7 @@ func (s *Server) handleReadyz(w http.ResponseWriter, r *http.Request) {
"present_count": sum.PresentCount,
"missing_count": sum.MissingCount,
"source": sum.Source,
"distribution": sum.Distribution,
"refresh": s.refreshSnapshot(),
}
if r.Method == http.MethodHead {
@@ -430,12 +471,6 @@ func (s *Server) beginRefresh() time.Time {
return now
}
func (s *Server) finishRefresh(started time.Time, err error, warnings []string) {
s.mu.Lock()
defer s.mu.Unlock()
s.finishRefreshLocked(started, err, warnings)
}
func (s *Server) finishRefreshLocked(started time.Time, err error, warnings []string) {
now := time.Now()
s.refreshInProgress = false