Commit c6a74626 authored by Andrei Mihu's avatar Andrei Mihu
Browse files

Automatically stop empty authoritative matches after a configurable amount of time.

parent dd0bcf98
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr
## [Unreleased]
### Changed
- Update username on leaderboard and tournament records when processing a score update.
- Automatically stop empty authoritative matches after a configurable amount of time.

## [2.9.1] - 2020-01-14
### Changed
+5 −0
Original line number Diff line number Diff line
@@ -210,6 +210,9 @@ func CheckConfig(logger *zap.Logger, config Config) map[string]string {
	if config.GetMatch().JoinMarkerDeadlineMs < 1 {
		logger.Fatal("Match join marker deadline must be >= 1", zap.Int("match.join_marker_deadline_ms", config.GetMatch().JoinMarkerDeadlineMs))
	}
	if config.GetMatch().MaxEmptySec < 0 {
		logger.Fatal("Match max idle seconds must be >= 0", zap.Int("match.max_empty_sec", config.GetMatch().MaxEmptySec))
	}
	if config.GetTracker().EventQueueSize < 1 {
		logger.Fatal("Tracker presence event queue size must be >= 1", zap.Int("tracker.event_queue_size", config.GetTracker().EventQueueSize))
	}
@@ -646,6 +649,7 @@ type MatchConfig struct {
	JoinAttemptQueueSize int `yaml:"join_attempt_queue_size" json:"join_attempt_queue_size" usage:"Size of the authoritative match buffer that limits the number of in-progress join attempts. Default 128."`
	DeferredQueueSize    int `yaml:"deferred_queue_size" json:"deferred_queue_size" usage:"Size of the authoritative match buffer that holds deferred message broadcasts until the end of each loop execution. Default 128."`
	JoinMarkerDeadlineMs int `yaml:"join_marker_deadline_ms" json:"join_marker_deadline_ms" usage:"Deadline in milliseconds that client authoritative match joins will wait for match handlers to acknowledge joins. Default 15000."`
	MaxEmptySec          int `yaml:"max_empty_sec" json:"max_empty_sec" usage:"Maximum number of consecutive seconds that authoritative matches are allowed to be empty before they are stopped. Default 900."`
}

// NewMatchConfig creates a new MatchConfig struct.
@@ -656,6 +660,7 @@ func NewMatchConfig() *MatchConfig {
		JoinAttemptQueueSize: 128,
		DeferredQueueSize:    128,
		JoinMarkerDeadlineMs: 15000,
		MaxEmptySec:          900,
	}
}

+0 −2
Original line number Diff line number Diff line
@@ -110,8 +110,6 @@ func AuthenticateDevice(ctx context.Context, logger *zap.Logger, db *sql.DB, dev
	if err != nil {
		if err == sql.ErrNoRows {
			found = false
			// No user account found.
			//return "", "", status.Error(codes.NotFound, "Device ID not found.")
		} else {
			logger.Error("Error looking up user by device ID.", zap.Error(err), zap.String("deviceID", deviceID), zap.String("username", username), zap.Bool("create", create))
			return "", "", false, status.Error(codes.Internal, "Error finding user account.")
+22 −1
Original line number Diff line number Diff line
@@ -89,6 +89,8 @@ type MatchHandler struct {
	tick int64

	// Control elements.
	emptyTicks    int
	maxEmptyTicks int
	inputCh       chan *MatchDataMessage
	ticker        *time.Ticker
	callCh        chan func(*MatchHandler)
@@ -149,6 +151,8 @@ func NewMatchHandler(logger *zap.Logger, config Config, matchRegistry MatchRegis

		tick: 0,

		emptyTicks:    0,
		maxEmptyTicks: rateInt * config.GetMatch().MaxEmptySec,
		inputCh:       make(chan *MatchDataMessage, config.GetMatch().InputQueueSize),
		// Ticker below.
		callCh:        make(chan func(mh *MatchHandler), config.GetMatch().CallQueueSize),
@@ -279,6 +283,23 @@ func loop(mh *MatchHandler) {
		}
	}

	// Check if the match has been empty too long.
	if mh.maxEmptyTicks > 0 {
		if mh.PresenceList.size.Load() == 0 {
			mh.emptyTicks++
			if mh.emptyTicks >= mh.maxEmptyTicks {
				// Match has reached its empty limit.
				mh.Stop()
				mh.logger.Warn("Stopping idle empty match", zap.Int64("tick", mh.tick), zap.Int("empty_ticks", mh.emptyTicks))
				return
			}
		} else if mh.emptyTicks > 0 {
			// If the match is not empty make sure to reset any counter value.
			// Only consecutive empty ticks should count towards the limit.
			mh.emptyTicks = 0
		}
	}

	mh.state = state
	mh.tick++
}