Skip to content

fix(matchmakingserver): expired invites only unlink their own battleground - #72

Merged
walkline merged 3 commits into
walkline:masterfrom
3kynox:fix/matchmaking-expiry-targeted-unlink
Sep 8, 2026
Merged

walkline merged 3 commits into
walkline:masterfrom
3kynox:fix/matchmaking-expiry-targeted-unlink

Conversation

@3kynox

@3kynox 3kynox commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

The invite-expiry loop calls RemovePlayerFromQueue(queueTypeID), which walks
every link of the player and removes them from any battleground of that
queue type — including a running match where they are an active participant,
so the service state diverges from the game server's. An invited player
already left the generic queue at invite time, so the only link to clean is
the battleground whose invite expired: unlink exactly that one.

The loop body is extracted into a tick method to make it testable; the test
checks that an active-match link survives the expiry of an invite to another
battleground of the same type.

Copilot AI review requested due to automatic review settings July 19, 2026 21:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes matchmaking state divergence by ensuring expired battleground invites only unlink the player from the specific battleground whose invite expired (rather than removing them from any battleground of the same queue type, including active matches). The expiry logic is extracted into a tick helper to make it unit-testable, and a regression test is added to verify active-match links survive unrelated invite expiry.

Changes:

  • Extracted the invite-expiry loop body into processExpiredBattlegroundInvitesTick for testability.
  • On invite expiry, unlinks only the expired battleground via removeBattlegroundLinkForPlayer instead of calling RemovePlayerFromQueue(queueTypeID).
  • Added a unit test to ensure an active-match battleground link is preserved when another invite expires.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
apps/matchmakingserver/service/battleground_service.go Refactors expiry processing into a tick method and changes unlink behavior to target only the expired battleground.
apps/matchmakingserver/service/battleground_service_test.go Adds coverage to prevent regressions where expiring an invite incorrectly unlinks an active match of the same queue type.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +842 to +843
case <-time.After(time.Second):
bgs, err := s.battlegroundsRepo.GetAllActiveBattlegrounds(ctx)
if err != nil {
log.Err(err).Msg("failed to get all active battlegrounds")
break
}
for _, bg := range bgs {
for _, invites := range bg.InvitedPlayersPerTeam {
for _, invite := range invites {
if time.Since(invite.InvitedTime) > time.Minute {
err = s.battlegroundsRepo.UpdateBattleground(
ctx,
bg.InstanceID,
repo.RealmWithBattlegroupKey{RealmID: bg.RealmID, BattlegroupID: bg.BattleGroupID},
func(b *battleground.Battleground) error {
b.RemovePlayerFromInvite(uint64(invite.GUID.LowGUID), uint32(invite.GUID.RealmID))
return nil
},
)
if err != nil {
log.Err(err).Msg("failed to remove invite from Battleground")
continue
}

err = s.RemovePlayerFromQueue(ctx, uint64(invite.GUID.LowGUID), uint32(invite.GUID.RealmID), bg.QueueTypeID)
if err != nil {
log.Err(err).Msg("failed to remove invited player from queue")
continue
}

slot := uint8(0) // TODO: provide real slot
err = s.eventsProducer.InviteExpired(&events.MatchmakingEventPlayersInviteExpiredPayload{
RealmID: uint32(invite.GUID.RealmID),
PlayersGUID: []guid.LowType{invite.GUID.LowGUID},
QueueSlotByPlayer: map[guid.LowType]uint8{invite.GUID.LowGUID: slot},
})
if err != nil {
log.Err(err).Msg("Failed to add invited player to queue")
}
}
s.processExpiredBattlegroundInvitesTick(ctx)
@3kynox

3kynox commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Done — switched to a ticker with an explicit Stop().

3kynox added 2 commits July 26, 2026 16:13
…round

The invite-expiry loop called RemovePlayerFromQueue with the queue type,
which walks every link of the player and removes them from any
battleground of that type - including a running match where the player
is an active participant. Unlink only the battleground whose invite
expired (the invited player left the generic queue at invite time, so
that link is the only one to clean).
@3kynox
3kynox force-pushed the fix/matchmaking-expiry-targeted-unlink branch from bdd7af2 to f4d87db Compare July 26, 2026 14:51
@3kynox

3kynox commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

Ping — still mergeable on master, and the ticker/Stop() change from the review is in. Anything else you'd like here?

@3kynox

3kynox commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Friendly ping — still applies cleanly and running in production on my cluster since July. One heads-up: #100 adds traces and an active-participant guard around the same expiry block, so whichever lands first, I'll rebase the other accordingly.

@walkline
walkline merged commit 865f441 into walkline:master Sep 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants