public void ReturnInternalIfPlayerJoinRequestNotFound() { // Setup the client such that it will claim there is no JoinRequest associated with one of the members of // the dequeued parties. _transaction .Setup(tx => tx.DequeueAsync(MatchmakingType, 1)) .Returns(Task.FromResult <IEnumerable <string> >(new List <string> { _soloParty.Id })); _memoryStoreClient.Setup(client => client.GetAsync <PartyJoinRequest>(_soloParty.Id)) .ReturnsAsync(new PartyJoinRequest(_soloParty, "", null)); _memoryStoreClient.Setup(client => client.GetAsync <PlayerJoinRequest>(SoloPartyLeader)) .ReturnsAsync((PlayerJoinRequest)null); // Verify that an Internal StatusCode was returned. var context = Util.CreateFakeCallContext(); var request = new PopWaitingPartiesRequest { Type = MatchmakingType, NumParties = 1 }; var exception = Assert.ThrowsAsync <RpcException>(() => _service.PopWaitingParties(request, context)); Assert.AreEqual(StatusCode.Internal, exception.StatusCode); Assert.AreEqual($"could not find JoinRequest for {SoloPartyLeader}", exception.Status.Detail); }
public override async Task <PopWaitingPartiesResponse> PopWaitingParties(PopWaitingPartiesRequest request, ServerCallContext context) { Reporter.GetWaitingPartiesInc(request.NumParties); if (request.NumParties == 0) { throw new RpcException(new Status(StatusCode.InvalidArgument, "must request at least one party")); } using (var memClient = _matchmakingMemoryStoreClientManager.GetClient()) { try { Task <IEnumerable <string> > dequeuedPartyIds; using (var tx = memClient.CreateTransaction()) { dequeuedPartyIds = tx.DequeueAsync(request.Type, request.NumParties); } dequeuedPartyIds.Wait(); // TODO investigate best approach to handling this error (leave as null, log warning, ignore?) IEnumerable <PartyJoinRequest> partyJoinRequests; try { partyJoinRequests = dequeuedPartyIds.Result .Select(async id => await memClient.GetAsync <PartyJoinRequest>(id) ?? throw new EntryNotFoundException(id)) .Select(t => t.Result) .ToList(); } catch (AggregateException ex) { throw ex.InnerException; } var playerJoinRequestsToUpdate = new List <PlayerJoinRequest>(); foreach (var partyJoinRequest in partyJoinRequests) { foreach (var(memberId, _) in partyJoinRequest.Party.MemberIdToPit) { var playerJoinRequest = await memClient.GetAsync <PlayerJoinRequest>(memberId) ?? throw new EntryNotFoundException(memberId); playerJoinRequest.State = MatchState.Matching; playerJoinRequestsToUpdate.Add(playerJoinRequest); } } using (var tx = memClient.CreateTransaction()) { tx.UpdateAll(playerJoinRequestsToUpdate); } var response = new PopWaitingPartiesResponse(); foreach (var partyJoinRequest in partyJoinRequests) { response.Parties.Add(ConvertToProto(partyJoinRequest)); } return(response); } catch (EntryNotFoundException ex) { // TODO: maybe add metrics for this. throw new RpcException(new Status(StatusCode.Internal, $"could not find JoinRequest for {ex.Id}")); } catch (InsufficientEntriesException) { Reporter.InsufficientWaitingPartiesInc(request.NumParties); throw new RpcException(new Status(StatusCode.ResourceExhausted, "requested number of parties players could not be met")); } catch (TransactionAbortedException) { throw new RpcException(new Status(StatusCode.Unavailable, "dequeue aborted due to concurrent modification; safe to retry")); } } }