public async Task <long> Handle(GetMaximumSequenceNumberCommand request, CancellationToken cancellationToken) { var number = await _sequenceNumberRepository .GetMaximumSequenceNumberAsync() .ConfigureAwait(false); return(number.Value); }
public async Task <ICabinetReader?> GetNextUnacknowledgedAsync(ActorId recipient, params DomainOrigin[] domains) { ArgumentNullException.ThrowIfNull(recipient, nameof(recipient)); ArgumentNullException.ThrowIfNull(domains, nameof(domains)); if (domains.Length == 0) { domains = Enum.GetValues <DomainOrigin>(); } var entryLookups = domains .Where(domain => domain != DomainOrigin.Unknown) .Select(domain => { var asLinq = _repositoryContainer .Catalog .GetItemLinqQueryable <CosmosCatalogEntry>(); var partitionKey = string.Join('_', recipient.Value, domain); var query = from catalogEntry in asLinq where catalogEntry.PartitionKey == partitionKey orderby catalogEntry.NextSequenceNumber select catalogEntry; var task = query .Take(1) .AsCosmosIteratorAsync() .FirstOrDefaultAsync(); return(new { domain, task }); }); var smallestDomain = DomainOrigin.Unknown; CosmosCatalogEntry?smallestEntry = null; foreach (var entryLookup in entryLookups.ToList()) { var catalogEntry = await entryLookup.task.ConfigureAwait(false); if (catalogEntry == null) { continue; } if (smallestEntry == null || smallestEntry.NextSequenceNumber > catalogEntry.NextSequenceNumber) { smallestEntry = catalogEntry; smallestDomain = entryLookup.domain; } } var maximumSequenceNumber = await _sequenceNumberRepository .GetMaximumSequenceNumberAsync() .ConfigureAwait(false); if (smallestEntry == null || smallestEntry.NextSequenceNumber > maximumSequenceNumber.Value) { return(null); } var cabinetKey = new CabinetKey( recipient, smallestDomain, new ContentType(smallestEntry.ContentType)); var cabinetReader = await GetCabinetReaderAsync(cabinetKey).ConfigureAwait(false); if (cabinetReader.CanPeek) { var nextItem = cabinetReader.Peek(); if (nextItem.SequenceNumber.Value == smallestEntry.NextSequenceNumber) { return(cabinetReader); } } // If SaveAsync fails to insert DataAvailable, for example due to crash/timeout, // there will be a catalog entry pointing to a non-existent item. await DeleteOldCatalogEntryAsync(smallestEntry).ConfigureAwait(false); return(null); }