open-match.dev/open-match@v1.8.1/examples/scale/backend/backend.go (about) 1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package backend 16 17 import ( 18 "context" 19 "fmt" 20 "io" 21 "math/rand" 22 "sync" 23 "time" 24 25 "github.com/sirupsen/logrus" 26 "go.opencensus.io/trace" 27 "open-match.dev/open-match/examples/scale/scenarios" 28 "open-match.dev/open-match/internal/appmain" 29 "open-match.dev/open-match/internal/config" 30 "open-match.dev/open-match/internal/rpc" 31 "open-match.dev/open-match/internal/telemetry" 32 "open-match.dev/open-match/pkg/pb" 33 ) 34 35 var ( 36 logger = logrus.WithFields(logrus.Fields{ 37 "app": "openmatch", 38 "component": "scale.backend", 39 }) 40 41 activeScenario = scenarios.ActiveScenario 42 43 mIterations = telemetry.Counter("scale_backend_iterations", "fetch match iterations") 44 mFetchMatchCalls = telemetry.Counter("scale_backend_fetch_match_calls", "fetch match calls") 45 mFetchMatchSuccesses = telemetry.Counter("scale_backend_fetch_match_successes", "fetch match successes") 46 mFetchMatchErrors = telemetry.Counter("scale_backend_fetch_match_errors", "fetch match errors") 47 mMatchesReturned = telemetry.Counter("scale_backend_matches_returned", "matches returned") 48 mSumTicketsReturned = telemetry.Counter("scale_backend_sum_tickets_returned", "tickets in matches returned") 49 mMatchesAssigned = telemetry.Counter("scale_backend_matches_assigned", "matches assigned") 50 mMatchAssignsFailed = telemetry.Counter("scale_backend_match_assigns_failed", "match assigns failed") 51 mBackfillsDeleted = telemetry.Counter("scale_backend_backfills_deleted", "backfills deleted") 52 mBackfillDeletesFailed = telemetry.Counter("scale_backend_backfill_deletes_failed", "backfill deletes failed") 53 ) 54 55 // Run triggers execution of functions that continuously fetch, assign and 56 // delete matches. 57 func BindService(p *appmain.Params, b *appmain.Bindings) error { 58 go run(p.Config()) 59 return nil 60 } 61 62 func run(cfg config.View) { 63 beConn, err := rpc.GRPCClientFromConfig(cfg, "api.backend") 64 if err != nil { 65 logger.Fatalf("failed to connect to Open Match Backend, got %v", err) 66 } 67 68 defer beConn.Close() 69 be := pb.NewBackendServiceClient(beConn) 70 71 feConn, err := rpc.GRPCClientFromConfig(cfg, "api.frontend") 72 if err != nil { 73 logger.Fatalf("failed to connect to Open Match Frontend, got %v", err) 74 } 75 76 defer feConn.Close() 77 fe := pb.NewFrontendServiceClient(feConn) 78 79 w := logger.Writer() 80 defer w.Close() 81 82 matchesToAssign := make(chan *pb.Match, 30000) 83 84 if activeScenario.BackendAssignsTickets { 85 for i := 0; i < 100; i++ { 86 go runAssignments(be, matchesToAssign) 87 } 88 } 89 90 backfillsToDelete := make(chan *pb.Backfill, 30000) 91 92 if activeScenario.BackendDeletesBackfills { 93 for i := 0; i < 100; i++ { 94 go runDeleteBackfills(fe, backfillsToDelete) 95 } 96 } 97 98 matchesToAcknowledge := make(chan *pb.Match, 30000) 99 100 if activeScenario.BackendAcknowledgesBackfills { 101 for i := 0; i < 100; i++ { 102 go runAcknowledgeBackfills(fe, matchesToAcknowledge, backfillsToDelete) 103 } 104 } 105 106 // Don't go faster than this, as it likely means that FetchMatches is throwing 107 // errors, and will continue doing so if queried very quickly. 108 for range time.Tick(time.Millisecond * 250) { 109 // Keep pulling matches from Open Match backend 110 profiles := activeScenario.Profiles() 111 var wg sync.WaitGroup 112 113 for _, p := range profiles { 114 wg.Add(1) 115 go func(wg *sync.WaitGroup, p *pb.MatchProfile) { 116 defer wg.Done() 117 runFetchMatches(be, p, matchesToAssign, matchesToAcknowledge) 118 }(&wg, p) 119 } 120 121 // Wait for all profiles to complete before proceeding. 122 wg.Wait() 123 telemetry.RecordUnitMeasurement(context.Background(), mIterations) 124 } 125 } 126 127 func runFetchMatches(be pb.BackendServiceClient, p *pb.MatchProfile, matchesToAssign chan<- *pb.Match, matchesToAcknowledge chan<- *pb.Match) { 128 ctx, span := trace.StartSpan(context.Background(), "scale.backend/FetchMatches") 129 defer span.End() 130 131 req := &pb.FetchMatchesRequest{ 132 Config: &pb.FunctionConfig{ 133 Host: "open-match-function", 134 Port: 50502, 135 Type: pb.FunctionConfig_GRPC, 136 }, 137 Profile: p, 138 } 139 140 telemetry.RecordUnitMeasurement(ctx, mFetchMatchCalls) 141 stream, err := be.FetchMatches(ctx, req) 142 if err != nil { 143 telemetry.RecordUnitMeasurement(ctx, mFetchMatchErrors) 144 logger.WithError(err).Error("failed to get available stream client") 145 return 146 } 147 148 for { 149 // Pull the Match 150 resp, err := stream.Recv() 151 if err == io.EOF { 152 telemetry.RecordUnitMeasurement(ctx, mFetchMatchSuccesses) 153 return 154 } 155 156 if err != nil { 157 telemetry.RecordUnitMeasurement(ctx, mFetchMatchErrors) 158 logger.WithError(err).Error("failed to get matches from stream client") 159 return 160 } 161 162 telemetry.RecordNUnitMeasurement(ctx, mSumTicketsReturned, int64(len(resp.GetMatch().Tickets))) 163 telemetry.RecordUnitMeasurement(ctx, mMatchesReturned) 164 165 if activeScenario.BackendAssignsTickets { 166 matchesToAssign <- resp.GetMatch() 167 } 168 169 if activeScenario.BackendAcknowledgesBackfills { 170 matchesToAcknowledge <- resp.GetMatch() 171 } 172 } 173 } 174 175 func runDeleteBackfills(fe pb.FrontendServiceClient, backfillsToDelete <-chan *pb.Backfill) { 176 for b := range backfillsToDelete { 177 if !activeScenario.BackfillDeleteCond(b) { 178 continue 179 } 180 181 ctx := context.Background() 182 _, err := fe.DeleteBackfill(ctx, &pb.DeleteBackfillRequest{BackfillId: b.Id}) 183 if err != nil { 184 logger.WithError(err).Errorf("failed to delete backfill: %s", b.Id) 185 telemetry.RecordUnitMeasurement(ctx, mBackfillDeletesFailed) 186 } else { 187 telemetry.RecordUnitMeasurement(ctx, mBackfillsDeleted) 188 } 189 } 190 } 191 192 func runAcknowledgeBackfills(fe pb.FrontendServiceClient, matchesToAcknowledge <-chan *pb.Match, backfillsToDelete chan<- *pb.Backfill) { 193 for m := range matchesToAcknowledge { 194 backfillId := m.Backfill.GetId() 195 if backfillId == "" { 196 continue 197 } 198 199 err := acknowledgeBackfill(fe, backfillId) 200 if err != nil { 201 logger.WithError(err).Errorf("failed to acknowledge backfill: %s", backfillId) 202 continue 203 } 204 205 if activeScenario.BackendDeletesBackfills { 206 backfillsToDelete <- m.Backfill 207 } 208 } 209 } 210 211 func acknowledgeBackfill(fe pb.FrontendServiceClient, backfillId string) error { 212 ctx, span := trace.StartSpan(context.Background(), "scale.frontend/AcknowledgeBackfill") 213 defer span.End() 214 215 _, err := fe.AcknowledgeBackfill(ctx, &pb.AcknowledgeBackfillRequest{ 216 BackfillId: backfillId, 217 Assignment: &pb.Assignment{ 218 Connection: fmt.Sprintf("%d.%d.%d.%d:2222", rand.Intn(256), rand.Intn(256), rand.Intn(256), rand.Intn(256)), 219 }, 220 }) 221 return err 222 } 223 224 func runAssignments(be pb.BackendServiceClient, matchesToAssign <-chan *pb.Match) { 225 ctx := context.Background() 226 227 for m := range matchesToAssign { 228 ids := []string{} 229 for _, t := range m.Tickets { 230 ids = append(ids, t.GetId()) 231 } 232 233 _, err := be.AssignTickets(context.Background(), &pb.AssignTicketsRequest{ 234 Assignments: []*pb.AssignmentGroup{ 235 { 236 TicketIds: ids, 237 Assignment: &pb.Assignment{ 238 Connection: fmt.Sprintf("%d.%d.%d.%d:2222", rand.Intn(256), rand.Intn(256), rand.Intn(256), rand.Intn(256)), 239 }, 240 }, 241 }, 242 }) 243 if err != nil { 244 telemetry.RecordUnitMeasurement(ctx, mMatchAssignsFailed) 245 logger.WithError(err).Error("failed to assign tickets") 246 continue 247 } 248 249 telemetry.RecordUnitMeasurement(ctx, mMatchesAssigned) 250 } 251 }