Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to disable relayed matches after matchmaker error, fixes for tests #1128

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/golangci-test.yml
@@ -0,0 +1,32 @@
name: golangci-test
on:
workflow_dispatch:
pull_request:

permissions:
contents: read
pull-requests: read

jobs:
golangci_test:
name: test
runs-on: ubuntu-latest
services:
cockroach:
image: timveil/cockroachdb-single-node:latest
env:
DATABASE_NAME: nakama
ports:
- 26257:26257
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: "stable"
cache: false
- name: Build binary
run: go build -trimpath -mod=vendor
- name: Run migrations
run: ./nakama migrate up --database.address "root:password@127.0.0.1:26257/nakama"
- name: golangci-test
run: go test ./...
Empty file.
5 changes: 2 additions & 3 deletions internal/gopher-lua/script_test.go
Expand Up @@ -18,12 +18,11 @@ var gluaTests []string = []string{
"coroutine.lua",
"db.lua",
"issues.lua",
"math.lua",
"os.lua",
"strings.lua",
"table.lua",
"vm.lua",
"math.lua",
"strings.lua",
"goto.lua",
}

var luaTests []string = []string{
Expand Down
22 changes: 12 additions & 10 deletions server/config.go
Expand Up @@ -977,20 +977,22 @@ func NewLeaderboardConfig() *LeaderboardConfig {
}

type MatchmakerConfig struct {
MaxTickets int `yaml:"max_tickets" json:"max_tickets" usage:"Maximum number of concurrent matchmaking tickets allowed per session or party. Default 3."`
IntervalSec int `yaml:"interval_sec" json:"interval_sec" usage:"How quickly the matchmaker attempts to form matches, in seconds. Default 15."`
MaxIntervals int `yaml:"max_intervals" json:"max_intervals" usage:"How many intervals the matchmaker attempts to find matches at the max player count, before allowing min count. Default 2."`
RevPrecision bool `yaml:"rev_precision" json:"rev_precision" usage:"Reverse matching precision. Default false."`
RevThreshold int `yaml:"rev_threshold" json:"rev_threshold" usage:"Reverse matching threshold. Default 1."`
MaxTickets int `yaml:"max_tickets" json:"max_tickets" usage:"Maximum number of concurrent matchmaking tickets allowed per session or party. Default 3."`
IntervalSec int `yaml:"interval_sec" json:"interval_sec" usage:"How quickly the matchmaker attempts to form matches, in seconds. Default 15."`
MaxIntervals int `yaml:"max_intervals" json:"max_intervals" usage:"How many intervals the matchmaker attempts to find matches at the max player count, before allowing min count. Default 2."`
RevPrecision bool `yaml:"rev_precision" json:"rev_precision" usage:"Reverse matching precision. Default false."`
RevThreshold int `yaml:"rev_threshold" json:"rev_threshold" usage:"Reverse matching threshold. Default 1."`
AllowRelayedMatchOnError bool `yaml:"allow_relayed_match_on_error" json:"allow_relayed_match_on_error" usage:"Allow creating relayed match when authoritative matchmaker error occurs. Default true."`
}

func NewMatchmakerConfig() *MatchmakerConfig {
return &MatchmakerConfig{
MaxTickets: 3,
IntervalSec: 15,
MaxIntervals: 2,
RevPrecision: false,
RevThreshold: 1,
MaxTickets: 3,
IntervalSec: 15,
MaxIntervals: 2,
RevPrecision: false,
RevThreshold: 1,
AllowRelayedMatchOnError: true,
}
}

Expand Down
67 changes: 39 additions & 28 deletions server/matchmaker.go
Expand Up @@ -338,34 +338,6 @@ func (m *LocalMatchmaker) Process() {
matchedEntries[len(matchedEntries)-1] = nil
matchedEntries = matchedEntries[:len(matchedEntries)-1]
i--
continue
}

// Remove all entries/indexes that have just matched.
ticketsToDelete := make(map[string]struct{}, len(currentMatchedEntries))
for _, entry := range currentMatchedEntries {
if _, ok := ticketsToDelete[entry.Ticket]; !ok {
ticketsToDelete[entry.Ticket] = struct{}{}
}
delete(m.indexes, entry.Ticket)
delete(m.activeIndexes, entry.Ticket)
m.revCache.Delete(entry.Ticket)
if sessionTickets, ok := m.sessionTickets[entry.Presence.SessionId]; ok {
if l := len(sessionTickets); l <= 1 {
delete(m.sessionTickets, entry.Presence.SessionId)
} else {
delete(sessionTickets, entry.Ticket)
}
}
if entry.PartyId != "" {
if partyTickets, ok := m.partyTickets[entry.PartyId]; ok {
if l := len(partyTickets); l <= 1 {
delete(m.partyTickets, entry.PartyId)
} else {
delete(partyTickets, entry.Ticket)
}
}
}
}
}

Expand All @@ -386,6 +358,11 @@ func (m *LocalMatchmaker) Process() {
tokenOrMatchID, isMatchID, err = fn(context.Background(), entries)
if err != nil {
m.logger.Error("Error running Matchmaker Matched hook.", zap.Error(err))
if !m.config.GetMatchmaker().AllowRelayedMatchOnError {
// Do not create relayed match
wg.Done()
return
}
}
}

Expand All @@ -398,6 +375,40 @@ func (m *LocalMatchmaker) Process() {
tokenOrMatchID, _ = token.SignedString([]byte(m.config.GetSession().EncryptionKey))
}

m.Lock()

if len(entries) > 0 {
batch := bluge.NewBatch()
// Remove all entries/indexes that have just matched.
for _, entry := range entries {
delete(m.indexes, entry.Ticket)
delete(m.activeIndexes, entry.Ticket)
batch.Delete(bluge.Identifier(entry.Ticket))
m.revCache.Delete(entry.Ticket)
if sessionTickets, ok := m.sessionTickets[entry.Presence.SessionId]; ok {
if l := len(sessionTickets); l <= 1 {
delete(m.sessionTickets, entry.Presence.SessionId)
} else {
delete(sessionTickets, entry.Ticket)
}
}
if entry.PartyId != "" {
if partyTickets, ok := m.partyTickets[entry.PartyId]; ok {
if l := len(partyTickets); l <= 1 {
delete(m.partyTickets, entry.PartyId)
} else {
delete(partyTickets, entry.Ticket)
}
}
}
}
if err := m.indexWriter.Batch(batch); err != nil {
m.logger.Error("error deleting matchmaker process entries batch", zap.Error(err))
}
}

m.Unlock()

users := make([]*rtapi.MatchmakerMatched_MatchmakerUser, 0, len(entries))
for _, entry := range entries {
users = append(users, &rtapi.MatchmakerMatched_MatchmakerUser{
Expand Down
29 changes: 0 additions & 29 deletions server/matchmaker_process.go
Expand Up @@ -303,21 +303,12 @@ func (m *LocalMatchmaker) processDefault(activeIndexCount int, activeIndexesCopy

matchedEntries = append(matchedEntries, currentMatchedEntries)

var batchSize int
batch := bluge.NewBatch()
// Mark tickets as unavailable for further use in this process iteration.
for _, currentMatchedEntry := range currentMatchedEntries {
if _, found := selectedTickets[currentMatchedEntry.Ticket]; found {
continue
}
selectedTickets[currentMatchedEntry.Ticket] = struct{}{}
batchSize++
batch.Delete(bluge.Identifier(currentMatchedEntry.Ticket))
}
if batchSize > 0 {
if err := m.indexWriter.Batch(batch); err != nil {
m.logger.Error("error deleting matchmaker process entries batch", zap.Error(err))
}
}

break
Expand Down Expand Up @@ -572,26 +563,6 @@ func (m *LocalMatchmaker) processCustom(activeIndexesCopy map[string]*Matchmaker
// Allow the custom function to determine which of the matches should be formed. All others will be discarded.
matchedEntries = m.runtime.matchmakerOverrideFunction(m.ctx, matchedEntries)

var batchSize int
var selectedTickets = map[string]string{}
batch := bluge.NewBatch()
// Mark tickets as unavailable for further use in this process iteration.
for _, matchedEntry := range matchedEntries {
for _, ticket := range matchedEntry {
if _, found := selectedTickets[ticket.Ticket]; found {
continue
}
selectedTickets[ticket.Ticket] = ticket.Ticket
batchSize++
batch.Delete(bluge.Identifier(ticket.Ticket))
}
}
if batchSize > 0 {
if err := m.indexWriter.Batch(batch); err != nil {
m.logger.Error("error deleting matchmaker process entries batch", zap.Error(err))
}
}

return matchedEntries, expiredActiveIndexes
}

Expand Down
2 changes: 1 addition & 1 deletion server/runtime_javascript_test.go
Expand Up @@ -73,7 +73,7 @@ m.foo = 'baz';
if err == nil {
t.Errorf("should've thrown an error")
}
if !strings.Contains(err.Error(), "TypeError: Cannot assign to read only property 'foo' at test:2:1(2)") {
if !strings.Contains(err.Error(), "TypeError: Cannot assign to read only property 'foo' at test") {
t.Errorf("should've thrown an error")
}
})
Expand Down
5 changes: 5 additions & 0 deletions server/storage_index_test.go
Expand Up @@ -55,6 +55,7 @@ func TestLocalStorageIndex_Write(t *testing.T) {
})
valueThree := string(valueThreeBytes)

metrics := &testMetrics{}
storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics)
if err != nil {
t.Fatal(err.Error())
Expand Down Expand Up @@ -207,6 +208,7 @@ func TestLocalStorageIndex_Write(t *testing.T) {
UpdateTime: timestamppb.New(ts),
}

metrics := &testMetrics{}
storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics)
if err != nil {
t.Fatal(err.Error())
Expand Down Expand Up @@ -331,6 +333,7 @@ func TestLocalStorageIndex_List(t *testing.T) {
})
valueThree := string(valueThreeBytes)

metrics := &testMetrics{}
storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics)
if err != nil {
t.Fatal(err.Error())
Expand Down Expand Up @@ -424,6 +427,7 @@ func TestLocalStorageIndex_List(t *testing.T) {
})
valueThree := string(valueThreeBytes)

metrics := &testMetrics{}
storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics)
if err != nil {
t.Fatal(err.Error())
Expand Down Expand Up @@ -508,6 +512,7 @@ func TestLocalStorageIndex_Delete(t *testing.T) {
})
valueOne := string(valueOneBytes)

metrics := &testMetrics{}
storageIdx, err := NewLocalStorageIndex(logger, db, &StorageConfig{}, metrics)
if err != nil {
t.Fatal(err.Error())
Expand Down