carlos / platform Public

Classify maintenance refusals as activator responses

Paul Campbell pushed by paul@keymail.dev 49046ecbbdc45c4a478f4594d450e80c182e92f8 parent 897fbc2
3 files changed, +9 −5
  • internal/activator/activator.go +3 −3
  • internal/activator/maintenance.go +3 −1
  • internal/activator/maintenance_test.go +3 −1
diff --git a/internal/activator/activator.go b/internal/activator/activator.go
index a22fd3e9a..20fe0e837 100644
--- a/internal/activator/activator.go
+++ b/internal/activator/activator.go
@@ -1354,7 +1354,7 @@ func (a *Service) serve(w http.ResponseWriter, r *http.Request, rt registry.Rout
fenced := a.fences[rt.Host] != 0
a.mu.Unlock()
if fenced {
- maintenanceResponse(w)
+ maintenanceResponse(w, r)
return true
}
// Per-host gating: only a hibernate-flagged instance is activator-managed;
@@ -1383,7 +1383,7 @@ func (a *Service) serve(w http.ResponseWriter, r *http.Request, rt registry.Rout
r.Header.Del(SidecarHeader)
if err := a.BeginSidecarRequest(r.Context(), rt); err != nil {
if errors.Is(err, ErrFenced) {
- maintenanceResponse(w)
+ maintenanceResponse(w, r)
return true
}
if errors.Is(err, context.Canceled) {
@@ -1411,7 +1411,7 @@ func (a *Service) serve(w http.ResponseWriter, r *http.Request, rt registry.Rout
var held *errLeaseHeld
switch {
case errors.Is(err, ErrFenced):
- maintenanceResponse(w)
+ maintenanceResponse(w, r)
case errors.As(err, &held):
retry := int(held.retryAfter/time.Second) + 1
w.Header().Set("Retry-After", strconv.Itoa(retry))
diff --git a/internal/activator/maintenance.go b/internal/activator/maintenance.go
index a643d3eb5..8981dbf77 100644
--- a/internal/activator/maintenance.go
+++ b/internal/activator/maintenance.go
@@ -6,6 +6,7 @@ import (
"net/http"
"time"
+ "github.com/carlosframework/platform/internal/edge"
"github.com/carlosframework/platform/internal/provision"
)
@@ -138,7 +139,8 @@ func (a *Service) rememberStopLocked(host string, observation *stopObservation)
}
a.stopHistory[host] = observation
}
-func maintenanceResponse(w http.ResponseWriter) {
+func maintenanceResponse(w http.ResponseWriter, r *http.Request) {
+ edge.MarkAnswered(r)
w.Header().Set("Cache-Control", "no-store")
w.Header().Set("Retry-After", "5")
http.Error(w, "instance failed to wake", http.StatusServiceUnavailable)
diff --git a/internal/activator/maintenance_test.go b/internal/activator/maintenance_test.go
index 82cc6cf0c..ae4533382 100644
--- a/internal/activator/maintenance_test.go
+++ b/internal/activator/maintenance_test.go
@@ -3,6 +3,7 @@ package activator
import (
"context"
"errors"
+ "github.com/carlosframework/platform/internal/edge"
"github.com/carlosframework/platform/internal/registry"
"net/http"
"net/http/httptest"
@@ -130,6 +131,7 @@ func TestMaintenanceFenceBlocksEveryAdmissionIncludingStaleRoute(t *testing.T) {
route.Kind = "service"
}
req := httptest.NewRequest("GET", "https://"+host+"/", nil)
+ req, answered := edge.WithAnswerFlag(req)
if sidecar {
req.Header.Set(SidecarHeader, "1")
}
@@ -142,7 +144,7 @@ func TestMaintenanceFenceBlocksEveryAdmissionIncludingStaleRoute(t *testing.T) {
} else {
handled = a.ServeHTTP(out, req, route, proxy)
}
- if !handled || proxied || out.Code != 503 || out.Header().Get("Cache-Control") != "no-store" {
+ if !handled || proxied || !*answered || out.Code != 503 || out.Header().Get("Cache-Control") != "no-store" {
t.Fatal("fence bypassed by stale or scheduled route")
}
}