Skip to content

Commit

Permalink
Update the simple game server to move itself back to the Ready state (#…
Browse files Browse the repository at this point in the history
…2409)

after allocation.

This allows us to test the "Reusing Allocated GameServers" integration
pattern.
  • Loading branch information
roberthbailey authored Dec 23, 2021
1 parent f7609c1 commit f27f15e
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 33 deletions.
2 changes: 1 addition & 1 deletion examples/simple-game-server/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ WITH_WINDOWS=1

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
project_path := $(dir $(mkfile_path))
server_tag = $(REGISTRY)/simple-game-server:0.5
server_tag = $(REGISTRY)/simple-game-server:0.6
ifeq ($(WITH_WINDOWS), 1)
server_tag_linux_amd64 = $(server_tag)-linux_amd64
else
Expand Down
20 changes: 11 additions & 9 deletions examples/simple-game-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ There are some text commands you can send the server to affect its behavior:
The server has a few configuration options that can be set via command line
flags. Some can also be set using environment variables.

| Flag | Environment Variable | Default |
| ------------------------- | -------------------- | ------- |
| port | PORT | 7654 |
| passthrough | PASSTHROUGH | false |
| ready | READY | true |
| automaticShutdownDelayMin | _n/a_ | 0 |
| readyDelaySec | _n/a_ | 0 |
| udp | UDP | true |
| tcp | TCP | false |
| Flag | Environment Variable | Default |
| -------------------------------------- | -------------------- | ------- |
| port | PORT | 7654 |
| passthrough | PASSTHROUGH | false |
| ready | READY | true |
| automaticShutdownDelaySec | _n/a_ | 0 |
| automaticShutdownDelayMin (deprecated) | _n/a_ | 0 |
| readyDelaySec | _n/a_ | 0 |
| readyIterations | _n/a_ | 0 |
| udp | UDP | true |
| tcp | TCP | false |

77 changes: 54 additions & 23 deletions examples/simple-game-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ func main() {
readyOnStart := flag.Bool("ready", true, "Mark this GameServer as Ready on startup")
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)")
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)")
readyDelaySec := flag.Int("readyDelaySec", 0, "If greater than zero and readyOnStart is true, wait this many seconds before marking the game server as ready")
readyDelaySec := flag.Int("readyDelaySec", 0, "If greater than zero, wait this many seconds each time before marking the game server as ready")
readyIterations := flag.Int("readyIterations", 0, "If greater than zero, return to a ready state this number of times before shutting down")
udp := flag.Bool("udp", true, "Server will listen on UDP")
tcp := flag.Bool("tcp", false, "Server will listen on TCP")

Expand All @@ -66,8 +67,12 @@ func main() {
tcp = &t
}

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

log.Print("Creating SDK instance")
Expand Down Expand Up @@ -108,15 +113,10 @@ func main() {
ready(s)
}


if *shutdownDelayMin > 0 && *shutdownDelaySec > 0 {
log.Fatalf("Cannot set both --automaticShutdownDelayMin and --automaticShutdownDelaySec")
}
if *shutdownDelayMin > 0 {
shutdownAfterAllocation(s, *shutdownDelayMin * 60)
}
if *shutdownDelaySec > 0 {
shutdownAfterAllocation(s, *shutdownDelaySec)
shutdownAfterNAllocations(s, *readyIterations, *shutdownDelaySec)
} else if *shutdownDelayMin > 0 {
shutdownAfterNAllocations(s, *readyIterations, *shutdownDelayMin * 60)
}

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

// shutdownAfterAllocation creates a callback to automatically shut down
// shutdownAfterNAllocations creates a callback to automatically shut down
// the server a specified number of seconds after the server becomes
// allocated.
func shutdownAfterAllocation(s *sdk.SDK, shutdownDelay int) {
err := s.WatchGameServer(func(gs *coresdk.GameServer) {
if gs.Status.State == "Allocated" {
time.Sleep(time.Duration(shutdownDelay) * time.Second)
shutdownErr := s.Shutdown()
if shutdownErr != nil {
log.Fatalf("Could not shutdown: %v", shutdownErr)
}
}
})
// allocated the Nth time.
//
// The algorithm is:
//
// 1. Move the game server back to ready N times after it is allocated
// 2. Shutdown the game server after the Nth time is becomes allocated
//
// This follows the integration pattern documented on the website at
// https://agones.dev/site/docs/integration-patterns/reusing-gameservers/
func shutdownAfterNAllocations(s *sdk.SDK, readyIterations, shutdownDelaySec int) {
gs, err := s.GameServer()
if err != nil {
log.Fatalf("Could not get game server: %v", err)
}
currentState := gs.Status.State
if err := s.WatchGameServer(func(gs *coresdk.GameServer) {
log.Printf("Watch Game Server callback fired. State = %s", gs.Status.State)
if currentState == "Ready" && gs.Status.State == "Allocated" {
log.Println("Game Server Allocated")
readyIterations--
// Run asynchronously
go func(iterations int) {
time.Sleep(time.Duration(shutdownDelaySec) * time.Second)

if iterations > 0 {
log.Println("Moving Game Server back to Ready")
readyErr := s.Ready()
if readyErr != nil {
log.Fatalf("Could not set game server to ready: %v", readyErr)
}
return
}

log.Println("Shutting down Game Server")
shutdownErr := s.Shutdown()
if shutdownErr != nil {
log.Fatalf("Could not shutdown game server: %v", shutdownErr)
}
os.Exit(0)
}(readyIterations)
}
currentState = gs.Status.State
}); err != nil {
log.Fatalf("Could not watch Game Server events, %v", err)
}
}
Expand Down

0 comments on commit f27f15e

Please sign in to comment.