60 строки
2.2 KiB
Go
60 строки
2.2 KiB
Go
package webapp
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// peerStatusResponse is the JSON returned at GET /api/peer/status.
|
|
// The shape matches distworker.PeerStatus exactly so the peer
|
|
// poller on the other end can decode it without a separate
|
|
// type. Kept here as a local view to keep the webapp package free
|
|
// of any concrete dependency on the distworker peer types; the
|
|
// fields are JSON-stable.
|
|
//
|
|
// Up == nil means "no probe has run yet" so peer workers that
|
|
// query this endpoint right after boot do not get a misleading
|
|
// "true" verdict while the selfcheck is still spinning up.
|
|
type peerStatusResponse struct {
|
|
WorkerID string `json:"worker_id"`
|
|
Up *bool `json:"up"`
|
|
ObservedAt *time.Time `json:"observed_at"`
|
|
}
|
|
|
|
// handlePeerStatus serves the most recent local selfcheck verdict
|
|
// to peer workers over HTTP. The endpoint is intentionally
|
|
// unauthenticated for now: a worker with basic auth configured
|
|
// (WORKER_LOGIN / WORKER_PASSWORD) still exposes the verdict
|
|
// because the path lives outside the /web/api/* prefix that the
|
|
// basic-auth middleware gates. This matches the
|
|
// "keep simple for local trusted workers if no peer auth exists
|
|
// yet" directive in
|
|
// docs/distributed/worker-to-worker-raft.md (slice 1).
|
|
//
|
|
// The endpoint never returns a 5xx: a runner that has not yet
|
|
// produced a verdict simply returns {"up": null, ...} so the
|
|
// peer poller can keep the slot in cache as "unknown" instead of
|
|
// treating the absence as a hard failure.
|
|
func (s *Server) handlePeerStatus(w http.ResponseWriter, _ *http.Request) {
|
|
resp := peerStatusResponse{}
|
|
if s.deps.Runner != nil {
|
|
up, at := s.deps.Runner.MasterStatus()
|
|
resp.WorkerID = s.deps.Runner.WorkerID()
|
|
resp.Up = up
|
|
if !at.IsZero() {
|
|
// Copy the timestamp so callers see a value
|
|
// (json omitempty is not used on purpose: an
|
|
// explicit zero time communicates "no probe" and
|
|
// an RFC3339 string communicates "probed at").
|
|
atCopy := at.UTC()
|
|
resp.ObservedAt = &atCopy
|
|
}
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(http.StatusOK)
|
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
|
s.deps.Logger.Printf("peer status encode: %v", err)
|
|
}
|
|
}
|