Unverified Commit 6d5aca79 authored by Lemon-miaow's avatar Lemon-miaow
Browse files

fix(operator): 有玩家在线时停服先在游戏里预告 30 秒,期间改回运行会取消

parent 4ae64cc2
Loading
Loading
Loading
Loading
+8 −0
Changes for deploy/crd/felis.lolicon.best_minecraftservers.yaml: 8 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -433,6 +433,14 @@ spec:
                  because the two endpoints fall in different reconcile passes.
                format: date-time
                type: string
              stopNoticeAt:
                description: |-
                  StopNoticeAt is when the operator told the players on a server that it is
                  about to stop (desiredState flipped to Stopped with players online). The stop
                  itself waits until StopNoticeWindow has passed since then; the stamp is cleared
                  once the server is scaled down, or when desiredState goes back to Running first.
                format: date-time
                type: string
            type: object
        type: object
    served: true
+12 −1
Changes for docs/troubleshooting.md: 12 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -284,8 +284,19 @@ panel shows `Stopped` means the game pod is still terminating (its shutdown save
can take a while); retry once `kubectl -n minecraft get pods -l
felis.lolicon.best/server=<name>` shows nothing.

A stop that leaves the server `Running` for about 30 s is the players' warning.
When desiredState turns `Stopped` and the RCON tally does not say the server is
empty, the operator sends everyone online a yellow chat line (`tellraw @a`),
stamps `status.stopNoticeAt`, records a `StopNotice` Event, and scales down
once `StopNoticeWindow` (30 s) has passed, with a last "stopping now" line
before the save. Starting the server again inside the window calls the stop
off, and the players are told so. An empty server, RCON off, or a probe or
broadcast that fails stops at once. Idle auto-stop only fires on an empty
server, so it never waits.

[GO-TESTED: `internal/maintenance`, `k8scluster_maintenance_test.go`,
`handlers_maintenance_test.go`, operator `maintenance_test.go`.]
`handlers_maintenance_test.go`, operator `maintenance_test.go`,
`stopnotice_test.go`.]

---

+5 −0
Changes for internal/apis/felis/v1alpha1/minecraftserver_types.go: 5 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -342,6 +342,11 @@ type MinecraftServerStatus struct {
	// or the server stops, so the empty-duration counter starts fresh each time
	// the server becomes unoccupied.
	EmptySince *metav1.Time `json:"emptySince,omitempty"`
	// StopNoticeAt is when the operator told the players on a server that it is
	// about to stop (desiredState flipped to Stopped with players online). The stop
	// itself waits until StopNoticeWindow has passed since then; the stamp is cleared
	// once the server is scaled down, or when desiredState goes back to Running first.
	StopNoticeAt *metav1.Time `json:"stopNoticeAt,omitempty"`
	// AutoRestarts counts how often the operator recreated the pod of a start
	// that timed out (at most MaxAutoRestarts, with a doubling backoff); reaching Ready or
	// stopping resets it.
+3 −0
Changes for internal/apis/felis/v1alpha1/zz_generated.deepcopy.go: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -121,6 +121,9 @@ func (in *MinecraftServerStatus) DeepCopyInto(out *MinecraftServerStatus) {
	if in.EmptySince != nil {
		out.EmptySince = in.EmptySince.DeepCopy()
	}
	if in.StopNoticeAt != nil {
		out.StopNoticeAt = in.StopNoticeAt.DeepCopy()
	}
	if in.LastAutoRestartAt != nil {
		out.LastAutoRestartAt = in.LastAutoRestartAt.DeepCopy()
	}
+2 −0
Changes for internal/operator/autorestart_test.go: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -122,6 +122,8 @@ func (p switchProber) Probe(context.Context, string, string) (operator.PlayerCou

func (switchProber) Save(context.Context, string, string) error { return nil }

func (switchProber) Broadcast(context.Context, string, string, string) error { return nil }

// A Running server keeps its phase and endpoint through two missed probes,
// re-probing every 10s; the third consecutive miss degrades it to Starting,
// and any success in between starts the count over.
Loading