private async Task HandleChangesAsync(IReadOnlyCollection <Change> changes, CancellationToken cancellationToken) { // This is needed bc the 'WithStartTime' isn't working for me on the ChangeFeedBuilder // This would only be run through the first time after deleting leases container and trying to // replay some events. if (changes.First().TimeStamp <= _epochStartTime) { changes = changes.Where(x => x.TimeStamp > _epochStartTime) .ToList().AsReadOnly(); } foreach (var change in changes) { // throw new ApplicationException(); var @event = change.GetEvent(_eventTypeResolver); var subscribedProjections = _projections .Where(projection => projection.IsSubscribedTo(@event)); foreach (var projection in subscribedProjections) { var viewNames = projection.GetViewNames(change.StreamInfo.Id, @event); foreach (var viewName in viewNames) { var handled = false; while (!handled) { var view = await _viewRepository.LoadViewAsync(viewName); // Only update if the LSN of the change is higher than the view. This will ensure // that changes are only processed once. // NOTE: This only works if there's just a single physical partition in Cosmos DB. // TODO: To support multiple partitions we need access to the leases to store // a LSN per lease in the view. This is not yet possible in the V3 SDK. if (view.IsNewerThanCheckpoint(change)) { projection.Apply(@event, view); view.UpdateCheckpoint(change); handled = await _viewRepository.SaveViewAsync(viewName, view); } else { // Already handled. handled = true; } if (!handled) { // Oh noos! Somebody changed the view in the meantime, let's wait and try again. await Task.Delay(100); } } } } } }
private async Task HandleChangesAsync(IReadOnlyCollection <Change> changes, CancellationToken cancellationToken) { foreach (var change in changes) { var @event = change.GetEvent(_eventTypeResolver); var subscribedProjections = _projections .Where(projection => projection.IsSubscribedTo(@event)).ToList(); if (subscribedProjections.Any()) { _viewRepository = new MSSQLViewRepository(new esdemo3Context()); } foreach (var projection in subscribedProjections) { var viewName = projection.GetViewName(change.StreamInfo.Id, @event); var handled = false; while (!handled) { var view = (MSSQLView)await _viewRepository.LoadViewAsync(viewName); // Only update if the LSN of the change is higher than the view. This will ensure // that changes are only processed once. // NOTE: This only works if there's just a single physical partition in Cosmos DB. // TODO: To support multiple partitions we need access to the leases to store // a LSN per lease in the view. This is not yet possible in the V3 SDK. if (view.IsNewerThanCheckpoint(change)) { projection.Apply(@event, view); view.UpdateCheckpoint(change); handled = await _viewRepository.SaveViewAsync(viewName, view); } else { // Already handled. handled = true; } if (!handled) { // Oh noos! Somebody changed the view in the meantime, let's wait and try again. await Task.Delay(100); } } } } }
public async Task ProcessChangesAsync(IChangeFeedObserverContext context, IReadOnlyList <Document> documents, CancellationToken cancellationToken) { foreach (var document in documents) { var @event = DeserializeEvent(document); foreach (var projection in _projections) { if (!projection.CanHandle(@event)) { continue; } var streamInfo = document.GetPropertyValue <JObject>("stream"); var viewName = projection.GetViewName(streamInfo["id"].Value <string>(), @event); var handled = false; while (!handled) { var view = await _viewRepository.LoadViewAsync(viewName); if (view.IsNewerThanCheckpoint(context.PartitionKeyRangeId, document)) { projection.Apply(@event, view); view.UpdateCheckpoint(context.PartitionKeyRangeId, document); handled = await _viewRepository.SaveViewAsync(viewName, view); } else { // Already handled. handled = true; } if (!handled) { // Oh noos! Somebody changed the view in the meantime, let's wait and try again. await Task.Delay(500); } } } } }