mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-14 18:22:05 +00:00
feat: add signal-bound server supervisor command
This commit is contained in:
+1
-1
@@ -1219,7 +1219,7 @@ the local/CI/community transport, not a silent production fallback.
|
|||||||
| 8.33 `[D:8.26,8.32]` | **IN PROGRESS.** Fleet scheduling now requires on-demand capacity and spreads Ready processes across zones with skew 1; the autoscaler preserves the two-process Ready floor | `deploy/k8s/base/fleet.yaml` and manifest tests reject interruptible placement and single-zone concentration structurally; regional node pools, forced node-loss testing and measured N+1 headroom remain |
|
| 8.33 `[D:8.26,8.32]` | **IN PROGRESS.** Fleet scheduling now requires on-demand capacity and spreads Ready processes across zones with skew 1; the autoscaler preserves the two-process Ready floor | `deploy/k8s/base/fleet.yaml` and manifest tests reject interruptible placement and single-zone concentration structurally; regional node pools, forced node-loss testing and measured N+1 headroom remain |
|
||||||
| 8.34 `[D:8.28,8.29]` | Native x86_64 benchmark of boot-to-process-ready and assignment-ready, p99 CPU/RSS/network and 60 Hz ticks; limits/node cap with 30% headroom | Measurements replace old estimates and certify density with no tick backlog |
|
| 8.34 `[D:8.28,8.29]` | Native x86_64 benchmark of boot-to-process-ready and assignment-ready, p99 CPU/RSS/network and 60 Hz ticks; limits/node cap with 30% headroom | Measurements replace old estimates and certify density with no tick backlog |
|
||||||
| 8.35 `[D:8.17,8.19,8.20,8.30,8.31]` | **IN PROGRESS.** Pure Go initial-connect policy decides ranked 30 s no-show cancellation with abandon ladder and casual 60 s bot start only when each team has a human; empty-team casual allocations cancel | `server/domain/noshow.go` covers wait/deadline boundaries, deterministic no-show/innocent ordering, ranked cooldown history and no pre-live rating action; persistent ticket restoration, allocation shutdown, bot spawn and live integration remain |
|
| 8.35 `[D:8.17,8.19,8.20,8.30,8.31]` | **IN PROGRESS.** Pure Go initial-connect policy decides ranked 30 s no-show cancellation with abandon ladder and casual 60 s bot start only when each team has a human; empty-team casual allocations cancel | `server/domain/noshow.go` covers wait/deadline boundaries, deterministic no-show/innocent ordering, ranked cooldown history and no pre-live rating action; persistent ticket restoration, allocation shutdown, bot spawn and live integration remain |
|
||||||
| 8.36 `[D:8.10,8.25,8.28,8.30]` | **IN PROGRESS.** Supervisor exposes an authenticated loopback-only drain request boundary that never places the token in command arguments/logs and rejects remote/partial/query-bearing configurations; the base now includes a two-Ready PodDisruptionBudget; `Supervisor.Run` now orchestrates drain-before-kill with a bounded grace deadline | `server/supervisor/`, `server_control.gd` and `deploy/k8s/base/game-server-pdb.yaml` cover bearer-token enforcement, loopback URL validation, secret-safe configuration, missing drain credentials, readiness transitions, Ready-floor disruption protection, graceful child exit after drain and force-kill of an unresponsive child; signal wiring in an executable supervisor, 300 s/285 s production lifecycle, live PDB/Fleet drain and infrastructure-abort classification remain |
|
| 8.36 `[D:8.10,8.25,8.28,8.30]` | **IN PROGRESS.** Supervisor exposes an authenticated loopback-only drain request boundary that never places the token in command arguments/logs and rejects remote/partial/query-bearing configurations; the base now includes a two-Ready PodDisruptionBudget; `Supervisor.Run` and `cmd/game-server-supervisor` now orchestrate signal-bound drain-before-kill with a bounded grace deadline | `server/supervisor/`, `server/cmd/game-server-supervisor/`, `server_control.gd` and `deploy/k8s/base/game-server-pdb.yaml` cover bearer-token enforcement, loopback URL validation, secret-safe configuration, missing drain credentials, readiness transitions, Ready-floor disruption protection, graceful child exit after drain and force-kill of an unresponsive child; live 300 s/285 s lifecycle, PDB/Fleet drain and infrastructure-abort classification remain |
|
||||||
| 8.37 `[D:8.5,8.10,8.25,8.26,8.31]` | Horizontally scaled primary control plane + warm standby, EU/NA fleets, RPO <=5 m/RTO <=30 m; signed result annotation/reconciliation preserves delivery outages | Restore/failover meet targets; live simulation continues; valid delayed result commits exactly once after recovery |
|
| 8.37 `[D:8.5,8.10,8.25,8.26,8.31]` | Horizontally scaled primary control plane + warm standby, EU/NA fleets, RPO <=5 m/RTO <=30 m; signed result annotation/reconciliation preserves delivery outages | Restore/failover meet targets; live simulation continues; valid delayed result commits exactly once after recovery |
|
||||||
| 8.38 `[D:7.7,8.26,8.36,8.37]` | Provider migration after Valve approves both providers' EU/NA POPs/certs and public UDP: restore, validate coordinator trust, switch allocations, drain old | Both geographies complete Hosted-SDR matches on new provider and no old-provider live match is terminated |
|
| 8.38 `[D:7.7,8.26,8.36,8.37]` | Provider migration after Valve approves both providers' EU/NA POPs/certs and public UDP: restore, validate coordinator trust, switch allocations, drain old | Both geographies complete Hosted-SDR matches on new provider and no old-provider live match is terminated |
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cosmic-clash/cosmic-clash/server/supervisor"
|
||||||
|
)
|
||||||
|
|
||||||
|
const usageText = `Usage: game-server-supervisor [options] -- <game-server-command> [args...]
|
||||||
|
|
||||||
|
The child command is started only after an allocated Agones endpoint has been
|
||||||
|
validated and, when configured, an explicit process-ready probe succeeds.
|
||||||
|
SIGTERM/SIGINT requests authenticated drain before the bounded grace deadline.
|
||||||
|
`
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
args := os.Args[1:]
|
||||||
|
separator := -1
|
||||||
|
for i, arg := range args {
|
||||||
|
if arg == "--" {
|
||||||
|
separator = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if separator < 0 || separator == len(args)-1 {
|
||||||
|
fmt.Fprint(os.Stderr, usageText)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
options := flag.NewFlagSet("game-server-supervisor", flag.ContinueOnError)
|
||||||
|
options.SetOutput(os.Stderr)
|
||||||
|
sdkBaseURL := options.String("sdk-base-url", "", "Agones SDK REST base URL; empty enables direct mode")
|
||||||
|
readyURL := options.String("ready-url", "", "explicit process-ready probe URL")
|
||||||
|
drainURL := options.String("drain-url", "", "loopback drain URL")
|
||||||
|
drainTokenEnv := options.String("drain-token-env", "COSMIC_CLASH_DRAIN_TOKEN", "environment variable containing the drain bearer token")
|
||||||
|
transport := options.String("transport", "enet", "enet or steam_sdr")
|
||||||
|
grace := options.Duration("drain-grace", supervisor.DefaultDrainGrace, "maximum graceful drain duration")
|
||||||
|
if err := options.Parse(args[:separator]); err != nil {
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
token := ""
|
||||||
|
if *drainTokenEnv != "" {
|
||||||
|
token = os.Getenv(*drainTokenEnv)
|
||||||
|
}
|
||||||
|
s, err := supervisor.New(supervisor.Config{
|
||||||
|
Command: args[separator+1:],
|
||||||
|
SDKBaseURL: *sdkBaseURL,
|
||||||
|
ReadyURL: *readyURL,
|
||||||
|
DrainURL: *drainURL,
|
||||||
|
DrainToken: token,
|
||||||
|
Transport: *transport,
|
||||||
|
ReadyTimeout: 30 * time.Second,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "game-server-supervisor: %v\n", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
if err := s.Run(ctx, *grace); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "game-server-supervisor: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cosmic-clash/cosmic-clash/server/supervisor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSupervisorCommandUsesTheSameProductionGraceDefault(t *testing.T) {
|
||||||
|
if supervisor.DefaultDrainGrace != 285*1000000000 {
|
||||||
|
t.Fatalf("unexpected production drain grace: %s", supervisor.DefaultDrainGrace)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user