public void SplitsAndJoinsEmpty() { var initial = new GroupMembership() { Destination = new AzureADGroup { ObjectId = Guid.NewGuid() }, SyncJobPartitionKey = Guid.NewGuid().ToString(), SyncJobRowKey = Guid.NewGuid().ToString(), }; var split = initial.Split(); Assert.AreEqual(1, split.Length); Assert.AreEqual(0, split.Single().SourceMembers.Count); Assert.AreEqual(initial.Destination, split.Single().Destination); Assert.AreEqual(initial.SyncJobRowKey, split.Single().SyncJobRowKey); Assert.AreEqual(initial.SyncJobPartitionKey, split.Single().SyncJobPartitionKey); Assert.IsTrue(split.Single().IsLastMessage); var rejoined = GroupMembership.Merge(split); Assert.AreEqual(0, rejoined.SourceMembers.Count); Assert.AreEqual(initial.Destination, rejoined.Destination); Assert.AreEqual(initial.SyncJobRowKey, rejoined.SyncJobRowKey); Assert.AreEqual(initial.SyncJobPartitionKey, rejoined.SyncJobPartitionKey); CollectionAssert.AreEqual(initial.SourceMembers, rejoined.SourceMembers); }
public void SplitsAndJoins() { var initial = MockGroupMembershipHelper.MockGroupMembership(); var split = initial.Split(); Assert.AreEqual((UserCount / ChunkSize) + 1, split.Length); foreach (var chunk in split) { Assert.AreEqual(initial.Sources, chunk.Sources); Assert.AreEqual(initial.Destination, chunk.Destination); Assert.AreEqual(initial.SyncJobRowKey, chunk.SyncJobRowKey); Assert.AreEqual(initial.SyncJobPartitionKey, chunk.SyncJobPartitionKey); Assert.IsFalse(chunk.Errored); } foreach (var nonlastChunk in split.Take(split.Length - 1)) { Assert.IsFalse(nonlastChunk.IsLastMessage); Assert.AreEqual(ChunkSize, nonlastChunk.SourceMembers.Count); } Assert.IsTrue(split.Last().IsLastMessage); Assert.AreEqual(UserCount % ChunkSize, split.Last().SourceMembers.Count); var rejoined = GroupMembership.Merge(split); Assert.AreEqual(initial.Sources, rejoined.Sources); Assert.AreEqual(initial.Destination, rejoined.Destination); Assert.AreEqual(initial.SyncJobRowKey, rejoined.SyncJobRowKey); Assert.AreEqual(initial.SyncJobPartitionKey, rejoined.SyncJobPartitionKey); CollectionAssert.AreEqual(initial.SourceMembers, rejoined.SourceMembers); Assert.IsFalse(rejoined.Errored); }
public void RoundTripSerialization() { var initial = MockGroupMembershipHelper.MockGroupMembership(); var split = JsonConvert.DeserializeObject <GroupMembership[]>(JsonConvert.SerializeObject(initial.Split())); Assert.AreEqual((UserCount / ChunkSize) + 1, split.Length); foreach (var chunk in split) { Assert.AreEqual(initial.Destination, chunk.Destination); Assert.AreEqual(initial.SyncJobRowKey, chunk.SyncJobRowKey); Assert.AreEqual(initial.SyncJobPartitionKey, chunk.SyncJobPartitionKey); } foreach (var nonlastChunk in split.Take(split.Length - 1)) { Assert.IsFalse(nonlastChunk.IsLastMessage); Assert.AreEqual(ChunkSize, nonlastChunk.SourceMembers.Count); } Assert.IsTrue(split.Last().IsLastMessage); Assert.AreEqual(UserCount % ChunkSize, split.Last().SourceMembers.Count); var rejoined = GroupMembership.Merge(split); Assert.AreEqual(initial.Destination, rejoined.Destination); Assert.AreEqual(initial.SyncJobRowKey, rejoined.SyncJobRowKey); Assert.AreEqual(initial.SyncJobPartitionKey, rejoined.SyncJobPartitionKey); CollectionAssert.AreEqual(initial.SourceMembers, rejoined.SourceMembers); }
public async Task HandleNewMessage(GroupMembershipMessage body, IMessageSession messageSession) { var sessionId = messageSession.SessionId; _receivedMessages.AddOrUpdate(sessionId, new List <GroupMembershipMessage> { body }, (key, messages) => { messages.Add(body); return(messages); }); //Console.WriteLine($"Session {sessionId} got {body.Body.SourceMembers.Count} users."); if (body.Body.IsLastMessage) { if (!_receivedMessages.TryRemove(sessionId, out var allReceivedMessages)) { // someone else got to it first. shouldn't happen, but it's good to be prepared. return; } // remove this message-renewing logic once we can verify that the new, longer message leases work. var source = new CancellationTokenSource(); var cancellationToken = source.Token; var renew = RenewMessages(messageSession, allReceivedMessages, cancellationToken); var received = GroupMembership.Merge(allReceivedMessages.Select(x => x.Body)); try { await _graphUpdater.CalculateDifference(received); // If it succeeded, complete all the messages and close the session await messageSession.CompleteAsync(allReceivedMessages.Select(x => x.LockToken)); await messageSession.CloseAsync(); } finally { source.Cancel(); } } }
public async Task <GroupMembershipMessageResponse> HandleNewMessageAsync(GroupMembershipMessage body, string messageSessionId) { if (body.IsCancelationMessage) { _receivedMessages.TryRemove(messageSessionId, out _); return(new GroupMembershipMessageResponse()); } _loggingRepository.SyncJobProperties = new Dictionary <string, string>() { { "LockToken", body.LockToken }, { "RowKey", body.Body.SyncJobRowKey }, { "PartitionKey", body.Body.SyncJobPartitionKey }, { "TargetOfficeGroupId", body.Body.Destination.ObjectId.ToString() } }; var receivedSoFar = _receivedMessages.AddOrUpdate(messageSessionId, new List <GroupMembershipMessage> { body }, (key, messages) => { messages.Add(body); return(messages); }); var handleNewMessageResponse = new GroupMembershipMessageResponse() { ShouldCompleteMessage = false }; await _loggingRepository.LogMessageAsync(new LogMessage { RunId = body.Body.RunId, Message = $"Got a message in {nameof(MessageCollector)}. " + $"The message we just received has {body.Body.SourceMembers.Count} users and is {(body.Body.IsLastMessage ? "" : "not ")}the last message in its session. " + $"There are currently {_receivedMessages.Count} sessions in flight. " + $"The current session, the one with ID {messageSessionId}, has {receivedSoFar.Count} messages with {receivedSoFar.Sum(x => x.Body.SourceMembers.Count)} users in total." }); if (body.Body.IsLastMessage) { if (!_receivedMessages.TryRemove(messageSessionId, out var allReceivedMessages)) { // someone else got to it first. shouldn't happen, but it's good to be prepared. return(handleNewMessageResponse); } var received = GroupMembership.Merge(allReceivedMessages.Select(x => x.Body)); await _loggingRepository.LogMessageAsync(new LogMessage { RunId = body.Body.RunId, Message = $"This message completed the session, so I'm going to sync {received.SourceMembers.Count} users." }); handleNewMessageResponse.CompletedGroupMembershipMessages = allReceivedMessages; handleNewMessageResponse.ShouldCompleteMessage = true; return(handleNewMessageResponse); } else { await _loggingRepository.LogMessageAsync(new LogMessage { RunId = body.Body.RunId, Message = "This is not the last message, so not doing anything right now." }); } _loggingRepository.SyncJobProperties = null; return(handleNewMessageResponse); }