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) } }