Skip to content

Commit f27f15e

Browse files
author
Robert Bailey
authored
Update the simple game server to move itself back to the Ready state (agones-dev#2409)
after allocation. This allows us to test the "Reusing Allocated GameServers" integration pattern.
1 parent f7609c1 commit f27f15e

3 files changed

Lines changed: 66 additions & 33 deletions

File tree

‎examples/simple-game-server/Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ WITH_WINDOWS=1
3535

3636
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
3737
project_path := $(dir $(mkfile_path))
38-
server_tag = $(REGISTRY)/simple-game-server:0.5
38+
server_tag = $(REGISTRY)/simple-game-server:0.6
3939
ifeq ($(WITH_WINDOWS), 1)
4040
server_tag_linux_amd64 = $(server_tag)-linux_amd64
4141
else

‎examples/simple-game-server/README.md‎

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@ There are some text commands you can send the server to affect its behavior:
3939
The server has a few configuration options that can be set via command line
4040
flags. Some can also be set using environment variables.
4141

42-
| Flag | Environment Variable | Default |
43-
| ------------------------- | -------------------- | ------- |
44-
| port | PORT | 7654 |
45-
| passthrough | PASSTHROUGH | false |
46-
| ready | READY | true |
47-
| automaticShutdownDelayMin | _n/a_ | 0 |
48-
| readyDelaySec | _n/a_ | 0 |
49-
| udp | UDP | true |
50-
| tcp | TCP | false |
42+
| Flag | Environment Variable | Default |
43+
| -------------------------------------- | -------------------- | ------- |
44+
| port | PORT | 7654 |
45+
| passthrough | PASSTHROUGH | false |
46+
| ready | READY | true |
47+
| automaticShutdownDelaySec | _n/a_ | 0 |
48+
| automaticShutdownDelayMin (deprecated) | _n/a_ | 0 |
49+
| readyDelaySec | _n/a_ | 0 |
50+
| readyIterations | _n/a_ | 0 |
51+
| udp | UDP | true |
52+
| tcp | TCP | false |
5153

‎examples/simple-game-server/main.go‎

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ func main() {
4141
readyOnStart := flag.Bool("ready", true, "Mark this GameServer as Ready on startup")
4242
shutdownDelayMin := flag.Int("automaticShutdownDelayMin", 0, "[Deprecated] If greater than zero, automatically shut down the server this many minutes after the server becomes allocated (please use automaticShutdownDelaySec instead)")
4343
shutdownDelaySec := flag.Int("automaticShutdownDelaySec", 0, "If greater than zero, automatically shut down the server this many seconds after the server becomes allocated (cannot be used if automaticShutdownDelayMin is set)")
44-
readyDelaySec := flag.Int("readyDelaySec", 0, "If greater than zero and readyOnStart is true, wait this many seconds before marking the game server as ready")
44+
readyDelaySec := flag.Int("readyDelaySec", 0, "If greater than zero, wait this many seconds each time before marking the game server as ready")
45+
readyIterations := flag.Int("readyIterations", 0, "If greater than zero, return to a ready state this number of times before shutting down")
4546
udp := flag.Bool("udp", true, "Server will listen on UDP")
4647
tcp := flag.Bool("tcp", false, "Server will listen on TCP")
4748

@@ -66,8 +67,12 @@ func main() {
6667
tcp = &t
6768
}
6869

69-
if !*udp && !*tcp {
70-
log.Fatalf("No protocol enabled, exiting")
70+
// Check for incompatible flags.
71+
if *shutdownDelayMin > 0 && *shutdownDelaySec > 0 {
72+
log.Fatalf("Cannot set both --automaticShutdownDelayMin and --automaticShutdownDelaySec")
73+
}
74+
if *readyIterations > 0 && *shutdownDelayMin <= 0 && *shutdownDelaySec <= 0 {
75+
log.Fatalf("Must set a shutdown delay if using ready iterations")
7176
}
7277

7378
log.Print("Creating SDK instance")
@@ -108,15 +113,10 @@ func main() {
108113
ready(s)
109114
}
110115

111-
112-
if *shutdownDelayMin > 0 && *shutdownDelaySec > 0 {
113-
log.Fatalf("Cannot set both --automaticShutdownDelayMin and --automaticShutdownDelaySec")
114-
}
115-
if *shutdownDelayMin > 0 {
116-
shutdownAfterAllocation(s, *shutdownDelayMin * 60)
117-
}
118116
if *shutdownDelaySec > 0 {
119-
shutdownAfterAllocation(s, *shutdownDelaySec)
117+
shutdownAfterNAllocations(s, *readyIterations, *shutdownDelaySec)
118+
} else if *shutdownDelayMin > 0 {
119+
shutdownAfterNAllocations(s, *readyIterations, *shutdownDelayMin * 60)
120120
}
121121

122122
// Prevent the program from quitting as the server is listening on goroutines.
@@ -131,20 +131,51 @@ func doSignal() {
131131
os.Exit(0)
132132
}
133133

134-
// shutdownAfterAllocation creates a callback to automatically shut down
134+
// shutdownAfterNAllocations creates a callback to automatically shut down
135135
// the server a specified number of seconds after the server becomes
136-
// allocated.
137-
func shutdownAfterAllocation(s *sdk.SDK, shutdownDelay int) {
138-
err := s.WatchGameServer(func(gs *coresdk.GameServer) {
139-
if gs.Status.State == "Allocated" {
140-
time.Sleep(time.Duration(shutdownDelay) * time.Second)
141-
shutdownErr := s.Shutdown()
142-
if shutdownErr != nil {
143-
log.Fatalf("Could not shutdown: %v", shutdownErr)
144-
}
145-
}
146-
})
136+
// allocated the Nth time.
137+
//
138+
// The algorithm is:
139+
//
140+
// 1. Move the game server back to ready N times after it is allocated
141+
// 2. Shutdown the game server after the Nth time is becomes allocated
142+
//
143+
// This follows the integration pattern documented on the website at
144+
// https://agones.dev/site/docs/integration-patterns/reusing-gameservers/
145+
func shutdownAfterNAllocations(s *sdk.SDK, readyIterations, shutdownDelaySec int) {
146+
gs, err := s.GameServer()
147147
if err != nil {
148+
log.Fatalf("Could not get game server: %v", err)
149+
}
150+
currentState := gs.Status.State
151+
if err := s.WatchGameServer(func(gs *coresdk.GameServer) {
152+
log.Printf("Watch Game Server callback fired. State = %s", gs.Status.State)
153+
if currentState == "Ready" && gs.Status.State == "Allocated" {
154+
log.Println("Game Server Allocated")
155+
readyIterations--
156+
// Run asynchronously
157+
go func(iterations int) {
158+
time.Sleep(time.Duration(shutdownDelaySec) * time.Second)
159+
160+
if iterations > 0 {
161+
log.Println("Moving Game Server back to Ready")
162+
readyErr := s.Ready()
163+
if readyErr != nil {
164+
log.Fatalf("Could not set game server to ready: %v", readyErr)
165+
}
166+
return
167+
}
168+
169+
log.Println("Shutting down Game Server")
170+
shutdownErr := s.Shutdown()
171+
if shutdownErr != nil {
172+
log.Fatalf("Could not shutdown game server: %v", shutdownErr)
173+
}
174+
os.Exit(0)
175+
}(readyIterations)
176+
}
177+
currentState = gs.Status.State
178+
}); err != nil {
148179
log.Fatalf("Could not watch Game Server events, %v", err)
149180
}
150181
}

0 commit comments

Comments
 (0)