private void AssignPartyAsRequeued(GatewayInternalService.GatewayInternalServiceClient gatewayClient,
                                           WaitingParty party)
        {
            var assignRequest = new AssignDeploymentsRequest();

            assignRequest.Assignments.Add(new Assignment
            {
                Result = Assignment.Types.Result.Requeued,
                Party  = party.Party
            });
            gatewayClient.AssignDeployments(assignRequest);
        }
        protected override void DoMatch(GatewayInternalService.GatewayInternalServiceClient gatewayClient,
                                        DeploymentServiceClient deploymentServiceClient)
        {
            try
            {
                var resp = gatewayClient.PopWaitingParties(new PopWaitingPartiesRequest
                {
                    Type       = _tag,
                    NumParties = 1
                });
                Console.WriteLine($"Fetched {resp.Parties.Count} from gateway");

                foreach (var party in resp.Parties)
                {
                    Console.WriteLine("Attempting to match a retrieved party.");
                    var deployment = GetDeploymentWithTag(deploymentServiceClient, _tag);
                    if (deployment != null)
                    {
                        var assignRequest = new AssignDeploymentsRequest();
                        Console.WriteLine("Found a deployment, assigning it to the party.");
                        assignRequest.Assignments.Add(new Assignment
                        {
                            DeploymentId   = deployment.Id,
                            DeploymentName = deployment.Name,
                            Result         = Assignment.Types.Result.Matched,
                            Party          = party.Party
                        });
                        MarkDeploymentAsInUse(deploymentServiceClient, deployment);
                        gatewayClient.AssignDeployments(assignRequest);
                    }
                    else
                    {
                        Console.WriteLine(
                            $"Unable to find a deployment with tag {_tag} in project {_project}");
                        Console.WriteLine("Requeueing the party");
                        AssignPartyAsRequeued(gatewayClient, party);
                    }
                }
            }
            catch (RpcException e)
            {
                if (e.StatusCode != StatusCode.ResourceExhausted && e.StatusCode != StatusCode.Unavailable)
                {
                    throw;
                }

                /* Unable to get the requested number of parties - ignore. */
                Console.WriteLine("No parties available.");
                Thread.Sleep(TickMs);
            }
        }
        public void ContinueWithoutAssignmentIfJoinRequestHasBeenDeleted()
        {
            _memoryStoreClient
            .Setup(client => client.GetAsync <PlayerJoinRequest>(It.IsAny <string>()))
            .ReturnsAsync((PlayerJoinRequest)null);
            _memoryStoreClient
            .Setup(client => client.GetAsync <PartyJoinRequest>(_partyMatched.Id))
            .ReturnsAsync((PartyJoinRequest)null);

            var updated  = new List <Entry>();
            var requeued = new List <QueuedEntry>();
            var deleted  = new List <Entry>();

            _transaction.Setup(tx => tx.UpdateAll(It.IsAny <IEnumerable <Entry> >()))
            .Callback <IEnumerable <Entry> >(reqs => updated.AddRange(reqs));
            _transaction.Setup(tx => tx.EnqueueAll(It.IsAny <IEnumerable <QueuedEntry> >()))
            .Callback <IEnumerable <QueuedEntry> >(reqs => requeued.AddRange(reqs));
            _transaction.Setup(tx => tx.DeleteAll(It.IsAny <IEnumerable <Entry> >()))
            .Callback <IEnumerable <Entry> >(reqs => deleted.AddRange(reqs));

            var ctx = Util.CreateFakeCallContext();
            var req = new AssignDeploymentsRequest
            {
                Assignments =
                {
                    new Assignment
                    {
                        Party  = ConvertToProto(_partyMatched),
                        Result = Assignment.Types.Result.Matched
                    }
                }
            };
            var task = _service.AssignDeployments(req, ctx);

            Assert.That(task.IsCompleted);
            Assert.AreEqual(StatusCode.OK, ctx.Status.StatusCode);
            Assert.IsEmpty(updated);
            Assert.IsEmpty(deleted);
            Assert.IsEmpty(requeued);
        }
Exemple #4
0
        private AssignDeploymentsRequest ConstructAssignRequest(IEnumerable <WaitingParty> waitingParties,
                                                                string deployment)
        {
            var req = new AssignDeploymentsRequest();

            foreach (var waitingParty in waitingParties)
            {
                var assignment = new Assignment
                {
                    DeploymentId   = deployment,
                    DeploymentName = $"test_deployment_{deployment}",
                    Result         = Assignment.Types.Result.Matched,
                    Party          = waitingParty.Party
                };
                if (deployment == "requeue" && !_requeued.Contains(waitingParty.Party.Id))
                {
                    assignment.Result = Assignment.Types.Result.Requeued;
                    _requeued.Add(waitingParty.Party.Id);
                }
                req.Assignments.Add(assignment);
            }

            return(req);
        }
        public void CallAppropriateMemoryStoreMethods()
        {
            var startTime = (DateTime.UtcNow - DateTime.UnixEpoch).TotalMilliseconds;
            var updated   = new List <Entry>();
            var requeued  = new List <QueuedEntry>();
            var deleted   = new List <Entry>();

            _memoryStoreClient
            .Setup(client => client.GetAsync <PartyJoinRequest>(_partyMatched.Id)).ReturnsAsync(_matchedPartyJoinRequest);
            _memoryStoreClient
            .Setup(client => client.GetAsync <PartyJoinRequest>(_partyError.Id)).ReturnsAsync(_errorPartyJoinRequest);
            _memoryStoreClient
            .Setup(client => client.GetAsync <PartyJoinRequest>(_requeuePartyJoinRequest.Id))
            .ReturnsAsync(_requeuePartyJoinRequest);
            _memoryStoreClient
            .Setup(client => client.GetAsync <PlayerJoinRequest>(It.IsAny <string>()))
            .ReturnsAsync((string id) => new PlayerJoinRequest(id, "", "", null)
            {
                State = MatchState.Matching
            });
            _transaction.Setup(tx => tx.UpdateAll(It.IsAny <IEnumerable <Entry> >()))
            .Callback <IEnumerable <Entry> >(reqs => updated.AddRange(reqs));
            _transaction.Setup(tx => tx.EnqueueAll(It.IsAny <IEnumerable <QueuedEntry> >()))
            .Callback <IEnumerable <QueuedEntry> >(reqs => requeued.AddRange(reqs));
            _transaction.Setup(tx => tx.DeleteAll(It.IsAny <IEnumerable <Entry> >()))
            .Callback <IEnumerable <Entry> >(reqs => deleted.AddRange(reqs));

            var ctx = Util.CreateFakeCallContext();
            var req = new AssignDeploymentsRequest
            {
                Assignments =
                {
                    new Assignment
                    {
                        Party          = ConvertToProto(_partyMatched),
                        Result         = Assignment.Types.Result.Matched,
                        DeploymentId   = "1",
                        DeploymentName = "deployment1"
                    },
                    new Assignment
                    {
                        Party  = ConvertToProto(_partyError),
                        Result = Assignment.Types.Result.Error
                    },
                    new Assignment
                    {
                        Party  = ConvertToProto(_partyRequeue),
                        Result = Assignment.Types.Result.Requeued
                    }
                }
            };

            _service.AssignDeployments(req, ctx);
            Assert.AreEqual(StatusCode.OK, ctx.Status.StatusCode);
            _memoryStoreClient.Verify(client => client.GetAsync <PlayerJoinRequest>(It.IsAny <string>()), Times.Exactly(4));

            // We expect 6 entities to be updates. First 5 should be PlayerJoinRequests. The last should be the
            // PartyJoinRequest of the requeued party.
            Assert.AreEqual(5, updated.Count);
            var playerJoinRequests = new List <PlayerJoinRequest>();

            for (var i = 0; i < 4; i++)
            {
                Assert.IsInstanceOf <PlayerJoinRequest>(updated[i]);
                playerJoinRequests.Add((PlayerJoinRequest)updated[i]);
            }

            Assert.AreEqual(LeaderPartyMatched, playerJoinRequests[0].Id);
            Assert.AreEqual("1", playerJoinRequests[0].DeploymentId);
            Assert.AreEqual("deployment1", playerJoinRequests[0].DeploymentName);
            Assert.AreEqual(MatchState.Matched, playerJoinRequests[0].State);
            Assert.AreEqual(PlayerPartyMatched, playerJoinRequests[1].PlayerIdentity);
            Assert.AreEqual("1", playerJoinRequests[1].DeploymentId);
            Assert.AreEqual("deployment1", playerJoinRequests[1].DeploymentName);
            Assert.AreEqual(MatchState.Matched, playerJoinRequests[1].State);

            Assert.AreEqual(LeaderPartyError, playerJoinRequests[2].PlayerIdentity);
            Assert.AreEqual(MatchState.Error, playerJoinRequests[2].State);

            Assert.AreEqual(LeaderPartyRequeue, playerJoinRequests[3].PlayerIdentity);
            Assert.AreEqual(MatchState.Requested, playerJoinRequests[3].State);

            Assert.IsInstanceOf <PartyJoinRequest>(updated[4]);
            var updatedPartyRequest = (PartyJoinRequest)updated[4];

            Assert.AreEqual(_partyRequeue.Id, updatedPartyRequest.Id);
            Assert.AreEqual("type-requeue", updatedPartyRequest.Type);
            Assert.AreEqual("type-requeue", updatedPartyRequest.QueueName);
            Assert.AreEqual("type-requeue", updatedPartyRequest.QueueName);
            Assert.Greater((DateTime.UtcNow - DateTime.UnixEpoch).TotalMilliseconds, updatedPartyRequest.Score);
            Assert.Greater(updatedPartyRequest.Score, startTime);

            // We expect for the requeued PartyJoinRequest to be exactly the same as the updated one.
            Assert.AreEqual(1, requeued.Count);
            Assert.AreEqual(updatedPartyRequest, requeued[0]);

            // We expect for 2 PartyJoinRequests to have been deleted, one per each party which has reached a final
            // state.
            Assert.AreEqual(2, deleted.Count);
            Assert.AreEqual(_partyMatched.Id, deleted[0].Id);
            Assert.AreEqual(_partyError.Id, deleted[1].Id);

            _logger.Verify(logger => logger.Warning(It.IsAny <string>()), Times.Never);
        }
Exemple #6
0
        protected override void DoMatch(GatewayInternalService.GatewayInternalServiceClient gatewayClient,
                                        DeploymentServiceClient deploymentServiceClient)
        {
            try
            {
                var resp = gatewayClient.PopWaitingParties(new PopWaitingPartiesRequest
                {
                    Type       = _tag,
                    NumParties = 1
                });
                Console.WriteLine($"Fetched {resp.Parties.Count} from gateway");

                foreach (var party in resp.Parties)
                {
                    Console.WriteLine("Attempting to match a retrieved party.");
                    _analytics.Send("match", "party_matching", new Dictionary <string, string>
                    {
                        { "partyId", party.Party.Id },
                        { "queueType", _tag },
                        { "partyPhase", party.Party.CurrentPhase.ToString() },
                        { "matchRequestId", party.MatchRequestId }
                    }, party.Party.LeaderPlayerId);

                    foreach (var memberId in party.Party.MemberIds)
                    {
                        _analytics.Send("match", "player_matching", new Dictionary <string, string>
                        {
                            { "partyId", party.Party.Id },
                            { "queueType", _tag },
                            { "playerJoinRequestState", "Matching" },
                            { "matchRequestId", party.MatchRequestId }
                        }, memberId);
                    }

                    var deployment = GetDeploymentWithTag(deploymentServiceClient, _tag);
                    if (deployment != null)
                    {
                        var assignRequest = new AssignDeploymentsRequest();
                        Console.WriteLine("Found a deployment, assigning it to the party.");
                        assignRequest.Assignments.Add(new Assignment
                        {
                            DeploymentId   = deployment.Id,
                            DeploymentName = deployment.Name,
                            Result         = Assignment.Types.Result.Matched,
                            Party          = party.Party
                        });
                        MarkDeploymentAsInUse(deploymentServiceClient, deployment);
                        gatewayClient.AssignDeployments(assignRequest);
                        _analytics.Send("deployment", "deployment_in_use", new Dictionary <string, string>
                        {
                            { "spatialProjectId", _project },
                            { "deploymentName", deployment.Name },
                            { "deploymentId", deployment.Id }
                        });
                    }
                    else
                    {
                        Console.WriteLine(
                            $"Unable to find a deployment with tag {_tag} in project {_project}");
                        Console.WriteLine("Requeueing the party");
                        AssignPartyAsRequeued(gatewayClient, party);
                    }
                }
            }
            catch (RpcException e)
            {
                if (e.StatusCode != StatusCode.ResourceExhausted && e.StatusCode != StatusCode.Unavailable)
                {
                    throw;
                }

                /* Unable to get the requested number of parties - ignore. */
                Console.WriteLine("No parties available.");
                Thread.Sleep(TickMs);
            }
        }
Exemple #7
0
        public override async Task <AssignDeploymentsResponse> AssignDeployments(AssignDeploymentsRequest request,
                                                                                 ServerCallContext context)
        {
            try
            {
                using (var memClient = _matchmakingMemoryStoreClientManager.GetClient())
                {
                    var toUpdate = new List <Entry>();
                    foreach (var assignment in request.Assignments)
                    {
                        Reporter.AssignDeploymentInc(assignment.DeploymentId, assignment.Result);
                        foreach (var memberId in assignment.Party.MemberIds)
                        {
                            var playerJoinRequest = await memClient.GetAsync <PlayerJoinRequest>(memberId);

                            if (playerJoinRequest == null)
                            {
                                continue;
                            }
                            switch (assignment.Result)
                            {
                            case Assignment.Types.Result.Error:
                                playerJoinRequest.State = MatchState.Error;
                                break;

                            case Assignment.Types.Result.Matched:
                                playerJoinRequest.AssignMatch(assignment.DeploymentId, assignment.DeploymentName);
                                break;

                            case Assignment.Types.Result.Requeued:
                                playerJoinRequest.State = MatchState.Requested;
                                break;
                            }

                            toUpdate.Add(playerJoinRequest);
                        }
                    }

                    var toRequeue = new List <PartyJoinRequest>();
                    var toDelete  = new List <PartyJoinRequest>();

                    foreach (var assignment in request.Assignments)
                    {
                        var party            = assignment.Party;
                        var partyJoinRequest = await memClient.GetAsync <PartyJoinRequest>(party.Id);

                        if (partyJoinRequest == null)
                        {
                            // Party join request has been cancelled.
                            continue;
                        }
                        if (assignment.Result == Assignment.Types.Result.Requeued)
                        {
                            partyJoinRequest.RefreshQueueData();
                            toRequeue.Add(partyJoinRequest);
                            toUpdate.Add(partyJoinRequest);
                        }
                        else
                        {
                            // If the matchmaking process for this party has reached a final state, we should delete the
                            // PartyJoinRequest associated to it.
                            toDelete.Add(partyJoinRequest);
                        }
                    }

                    using (var tx = memClient.CreateTransaction())
                    {
                        tx.UpdateAll(toUpdate);
                        tx.EnqueueAll(toRequeue);
                        tx.DeleteAll(toDelete);
                    }
                }
            }
            catch (EntryNotFoundException e)
            {
                Reporter.AssignDeploymentNotFoundInc(e.Id);
                Log.Warning($"Attempted to assign deployment to nonexistent join request {e.Id}.");
                throw new RpcException(new Status(StatusCode.NotFound, "Join request does not exist"));
            }
            catch (TransactionAbortedException)
            {
                Reporter.TransactionAbortedInc("AssignDeployments");
                Log.Warning("Transaction aborted during deployment assignment.");
                throw new RpcException(new Status(StatusCode.Unavailable,
                                                  "assignment aborted due to concurrent modification; safe to retry"));
            }

            return(new AssignDeploymentsResponse());
        }
        public override async Task <AssignDeploymentsResponse> AssignDeployments(AssignDeploymentsRequest request,
                                                                                 ServerCallContext context)
        {
            try
            {
                using (var memClient = _matchmakingMemoryStoreClientManager.GetClient())
                {
                    var toUpdate = new List <Entry>();
                    foreach (var assignment in request.Assignments)
                    {
                        Reporter.AssignDeploymentInc(assignment.DeploymentId, assignment.Result);
                        foreach (var memberId in assignment.Party.MemberIds)
                        {
                            var playerJoinRequest = await memClient.GetAsync <PlayerJoinRequest>(memberId);

                            if (playerJoinRequest == null)
                            {
                                continue;
                            }
                            switch (assignment.Result)
                            {
                            case Assignment.Types.Result.Error:
                                playerJoinRequest.State = MatchState.Error;
                                break;

                            case Assignment.Types.Result.Matched:
                                playerJoinRequest.AssignMatch(assignment.DeploymentId, assignment.DeploymentName);
                                break;

                            case Assignment.Types.Result.Requeued:
                                playerJoinRequest.State = MatchState.Requested;
                                break;
                            }

                            toUpdate.Add(playerJoinRequest);
                        }
                    }

                    var toRequeue = new List <PartyJoinRequest>();
                    var toDelete  = new List <PartyJoinRequest>();

                    foreach (var assignment in request.Assignments)
                    {
                        var party            = assignment.Party;
                        var partyJoinRequest = await memClient.GetAsync <PartyJoinRequest>(party.Id);

                        if (partyJoinRequest == null)
                        {
                            // Party join request has been cancelled.
                            continue;
                        }

                        var eventAttributes = new Dictionary <string, string>
                        {
                            { "partyId", partyJoinRequest.Id },
                            { "matchRequestId", partyJoinRequest.MatchRequestId },
                            { "queueType", partyJoinRequest.Type },
                            { "partyPhase", partyJoinRequest.Party.CurrentPhase.ToString() }
                        };

                        if (assignment.Result == Assignment.Types.Result.Matched)
                        {
                            toDelete.Add(partyJoinRequest);

                            eventAttributes.Add("spatialProjectId", _project);
                            eventAttributes.Add("deploymentName", assignment.DeploymentName);
                            eventAttributes.Add("deploymentId", assignment.DeploymentId);
                            _analytics.Send("party_matched", eventAttributes, partyJoinRequest.Party.LeaderPlayerId);
                        }
                        else if (assignment.Result == Assignment.Types.Result.Requeued)
                        {
                            partyJoinRequest.RefreshQueueData();
                            toRequeue.Add(partyJoinRequest);
                            toUpdate.Add(partyJoinRequest);
                            _analytics.Send("party_requeued", eventAttributes, partyJoinRequest.Party.LeaderPlayerId);
                        }
                        else if (assignment.Result == Assignment.Types.Result.Error)
                        {
                            toDelete.Add(partyJoinRequest);
                            _analytics.Send("party_error", eventAttributes, partyJoinRequest.Party.LeaderPlayerId);
                        }
                        else
                        {
                            toDelete.Add(partyJoinRequest);
                        }
                    }

                    using (var tx = memClient.CreateTransaction())
                    {
                        tx.UpdateAll(toUpdate);
                        tx.EnqueueAll(toRequeue);
                        tx.DeleteAll(toDelete);
                    }

                    foreach (var playerJoinRequest in toUpdate.OfType <PlayerJoinRequest>())
                    {
                        var eventAttributes = new Dictionary <string, string>
                        {
                            { "partyId", playerJoinRequest.PartyId },
                            { "matchRequestId", playerJoinRequest.MatchRequestId },
                            { "queueType", playerJoinRequest.Type },
                            { "playerJoinRequestState", playerJoinRequest.State.ToString() }
                        };

                        switch (playerJoinRequest.State)
                        {
                        case MatchState.Matched:
                            eventAttributes.Add("spatialProjectId", _project);
                            eventAttributes.Add("deploymentName", playerJoinRequest.DeploymentName);
                            eventAttributes.Add("deploymentId", playerJoinRequest.DeploymentId);
                            _analytics.Send("player_matched", eventAttributes, playerJoinRequest.Id);
                            break;

                        case MatchState.Requested:
                            _analytics.Send("player_requeued", eventAttributes, playerJoinRequest.Id);
                            break;

                        case MatchState.Error:
                            _analytics.Send("player_error", eventAttributes, playerJoinRequest.Id);
                            break;
                        }
                    }
                }
            }
            catch (EntryNotFoundException e)
            {
                Reporter.AssignDeploymentNotFoundInc(e.Id);
                Log.Warning($"Attempted to assign deployment to nonexistent join request {e.Id}.");
                throw new RpcException(new Status(StatusCode.NotFound, "Join request does not exist"));
            }
            catch (TransactionAbortedException)
            {
                Reporter.TransactionAbortedInc("AssignDeployments");
                Log.Warning("Transaction aborted during deployment assignment.");
                throw new RpcException(new Status(StatusCode.Unavailable,
                                                  "assignment aborted due to concurrent modification; safe to retry"));
            }

            return(new AssignDeploymentsResponse());
        }
        protected override void DoMatch(GatewayInternalService.GatewayInternalServiceClient gatewayClient,
                                        DeploymentServiceClient deploymentServiceClient)
        {
            try
            {
                var resp = gatewayClient.PopWaitingParties(new PopWaitingPartiesRequest
                {
                    Type       = _tag,
                    NumParties = 1
                });
                Console.WriteLine($"Fetched {resp.Parties.Count} from gateway");

                foreach (var party in resp.Parties)
                {
                    Console.WriteLine($"Attempting to match a retrieved party of {party.Party.MemberIds.Count} players.");

                    bool requeue    = false;
                    var  deployment = GetDeploymentWithTag(deploymentServiceClient, _tag);
                    if (deployment != null)
                    {
                        var assignRequest = new AssignDeploymentsRequest();
                        Console.WriteLine("Found a deployment.");
                        int numPlayers = 0;
                        foreach (string tag in deployment.Tag)
                        {
                            if (tag.StartsWith(PlayersTag))
                            {
                                int.TryParse(tag.Split("_")[1], out numPlayers);
                                Console.WriteLine($"Deployment already has {numPlayers} in.");
                                break;
                            }
                        }

                        int totalPlayers = numPlayers + party.Party.MemberIds.Count;
                        if (totalPlayers <= PlayersPerDeployment)
                        {
                            if (numPlayers > 0)
                            {
                                Console.WriteLine($"Removing tag {PlayersTag}_{numPlayers}");
                                deployment.Tag.Remove($"{PlayersTag}_{numPlayers}");
                            }

                            if (totalPlayers == PlayersPerDeployment)
                            {
                                Console.WriteLine("Deployment is full, marking as in_use");
                                MarkDeploymentAsInUse(deploymentServiceClient, deployment);
                            }
                            else
                            {
                                Console.WriteLine($"Deployment isn't full, adding tag {PlayersTag}_{totalPlayers}");
                                deployment.Tag.Add($"{PlayersTag}_{totalPlayers}");
                                var req = new UpdateDeploymentRequest {
                                    Deployment = deployment
                                };
                                deploymentServiceClient.UpdateDeployment(req);
                            }

                            assignRequest.Assignments.Add(new Assignment
                            {
                                DeploymentId   = deployment.Id,
                                DeploymentName = deployment.Name,
                                Result         = Assignment.Types.Result.Matched,
                                Party          = party.Party
                            });
                            gatewayClient.AssignDeployments(assignRequest);
                        }
                        else
                        {
                            Console.WriteLine("Deployment does not have space for a party of this size.");
                            requeue = true;
                        }
                    }
                    else
                    {
                        Console.WriteLine($"Unable to find a deployment with tag {_tag} in project {_project}");
                        requeue = true;
                    }

                    if (requeue)
                    {
                        Console.WriteLine("Requeueing the party");
                        AssignPartyAsRequeued(gatewayClient, party);
                    }
                }
            }
            catch (RpcException e)
            {
                if (e.StatusCode != StatusCode.ResourceExhausted && e.StatusCode != StatusCode.Unavailable)
                {
                    throw;
                }

                /* Unable to get the requested number of parties - ignore. */
                Thread.Sleep(TickMs);
            }
        }