public async Task <long> Handle(GetMaximumSequenceNumberCommand request, CancellationToken cancellationToken)
        {
            var number = await _sequenceNumberRepository
                         .GetMaximumSequenceNumberAsync()
                         .ConfigureAwait(false);

            return(number.Value);
        }
Beispiel #2
0
        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);
        }