private async Task Process(Tracked <IStream> trackedStream) { var s = trackedStream.Value; if (s.Version == ExpectedVersion.NoStream) { trackedStream.Complete(); return; } if (trackedStream.Completed.IsCompleted) { return; } var version = _versions.GetOrAdd(s.Key, ExpectedVersion.EmptyStream); var origVersion = version; // read from latest snapshot var snapshotVersion = s.SnapshotVersion; if (version < snapshotVersion && _projection.Latest > s.SnapshotTimestamp) { version = snapshotVersion - 1; } if (s.Version <= ExpectedVersion.EmptyStream) { s.Version = 0; } if (version > s.Version) { _log?.Warn($"Stream {s.Key} update is version {s.Version}, behind projection version {version}", GetDetailedName()); } if (version < s.Version) { var t = await _eventStore.ReadStream <IEvent>(s, version + 1) .TakeWhile(_ => !_token.IsCancellationRequested) .Select(e => _projection.When(e)) .ToList() .Timeout(Configuration.Timeout) .LastOrDefaultAsync(); version += t.Count; await Task.WhenAll(t); _log?.Debug($"{s.Key}@{s.Version} <- {version}", $"{Parents.Select(p => p.Name).Aggregate((a, n) => a + n)}->{Name}"); if (!_versions.TryUpdate(s.Key, version, origVersion)) { throw new InvalidOperationException("Failed updating concurrent versions of projections"); } } trackedStream.Complete(); }