feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
Этот коммит содержится в:
59
internal/webapp/handlers_peer.go
Обычный файл
59
internal/webapp/handlers_peer.go
Обычный файл
@@ -0,0 +1,59 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user