/// <summary>
        /// Returns <see cref="BlobChangeFeedEvent"/>s as Pages.
        /// </summary>
        /// <param name="continuationToken">
        /// Throws an <see cref="ArgumentException"/>.  To use contination, call
        /// <see cref="BlobChangeFeedClient.GetChanges(string)"/>.
        /// </param>
        /// <param name="pageSizeHint">
        /// Page size.
        /// </param>
        /// <returns>
        /// <see cref="IEnumerable{Page}"/>.
        /// </returns>
        public override IEnumerable <Page <BlobChangeFeedEvent> > AsPages(string continuationToken = null, int?pageSizeHint = null)
        {
            if (continuationToken != null)
            {
                throw new ArgumentException($"Continuation not supported.  Use BlobChangeFeedClient.GetChanges(string) instead");
            }

            ChangeFeed changeFeed = _changeFeedFactory.BuildChangeFeed(
                async: false,
                _startTime,
                _endTime,
                _continuation)
                                    .EnsureCompleted();

            while (changeFeed.HasNext())
            {
                yield return(changeFeed.GetPage(
                                 async: false,
                                 pageSize: pageSizeHint ?? 512).EnsureCompleted());
            }
        }
Exemple #2
0
        /// <summary>
        /// Returns <see cref="BlobChangeFeedEvent"/>s as Pages.
        /// </summary>
        /// <param name="continuationToken">
        /// Throws an <see cref="ArgumentException"/>.  To use contination, call
        /// <see cref="BlobChangeFeedClient.GetChangesAsync(string)"/>.
        /// </param>
        /// <param name="pageSizeHint">
        /// Page size.
        /// </param>
        /// <returns>
        /// <see cref="IAsyncEnumerable{Page}"/>.
        /// </returns>
        public override async IAsyncEnumerable <Page <BlobChangeFeedEvent> > AsPages(
            string continuationToken = null,
            int?pageSizeHint         = null)
        {
            if (continuationToken != null)
            {
                throw new ArgumentException($"{nameof(continuationToken)} not supported.  Use BlobChangeFeedClient.GetChangesAsync(string) instead");
            }

            ChangeFeed changeFeed = await _changeFeedFactory.BuildChangeFeed(
                _startTime,
                _endTime,
                _continuation,
                async : true,
                cancellationToken : default)
                                    .ConfigureAwait(false);

            while (changeFeed.HasNext())
            {
                yield return(await changeFeed.GetPage(
                                 async : true,
                                 pageSize : pageSizeHint ?? Constants.ChangeFeed.DefaultPageSize).ConfigureAwait(false));
            }
        }
        public async Task <ChangeFeed> BuildChangeFeed(
            bool async,
            DateTimeOffset?startTime = default,
            DateTimeOffset?endTime   = default,
            string continuation      = default)
        {
            DateTimeOffset   lastConsumable;
            Queue <string>   years    = new Queue <string>();
            Queue <string>   segments = new Queue <string>();
            ChangeFeedCursor cursor   = null;

            // Create cursor
            if (continuation != null)
            {
                cursor = JsonSerializer.Deserialize <ChangeFeedCursor>(continuation);
                ValidateCursor(_containerClient, cursor);
                startTime = cursor.CurrentSegmentCursor.SegmentTime;
                endTime   = cursor.EndTime;
            }
            // Round start and end time if we are not using the cursor.
            else
            {
                startTime = startTime.RoundDownToNearestHour();
                endTime   = endTime.RoundUpToNearestHour();
            }

            // Check if Change Feed has been abled for this account.
            bool changeFeedContainerExists;

            if (async)
            {
                changeFeedContainerExists = await _containerClient.ExistsAsync().ConfigureAwait(false);
            }
            else
            {
                changeFeedContainerExists = _containerClient.Exists();
            }

            if (!changeFeedContainerExists)
            {
                throw new ArgumentException("Change Feed hasn't been enabled on this account, or is currently being enabled.");
            }

            // Get last consumable
            BlobClient       blobClient = _containerClient.GetBlobClient(Constants.ChangeFeed.MetaSegmentsPath);
            BlobDownloadInfo blobDownloadInfo;

            if (async)
            {
                blobDownloadInfo = await blobClient.DownloadAsync().ConfigureAwait(false);
            }
            else
            {
                blobDownloadInfo = blobClient.Download();
            }

            JsonDocument jsonMetaSegment;

            if (async)
            {
                jsonMetaSegment = await JsonDocument.ParseAsync(blobDownloadInfo.Content).ConfigureAwait(false);
            }
            else
            {
                jsonMetaSegment = JsonDocument.Parse(blobDownloadInfo.Content);
            }

            lastConsumable = jsonMetaSegment.RootElement.GetProperty("lastConsumable").GetDateTimeOffset();

            // Get year paths
            years = await GetYearPaths(async).ConfigureAwait(false);

            // Dequeue any years that occur before start time
            if (startTime.HasValue)
            {
                while (years.Count > 0 &&
                       years.Peek().ToDateTimeOffset() < startTime.RoundDownToNearestYear())
                {
                    years.Dequeue();
                }
            }

            // There are no years.
            if (years.Count == 0)
            {
                return(ChangeFeed.Empty());
            }

            while (segments.Count == 0 && years.Count > 0)
            {
                // Get Segments for year
                segments = await BlobChangeFeedExtensions.GetSegmentsInYear(
                    async : async,
                    containerClient : _containerClient,
                    yearPath : years.Dequeue(),
                    startTime : startTime,
                    endTime : BlobChangeFeedExtensions.MinDateTime(lastConsumable, endTime))
                           .ConfigureAwait(false);
            }

            // We were on the last year, and there were no more segments.
            if (segments.Count == 0)
            {
                return(ChangeFeed.Empty());
            }

            Segment currentSegment = await _segmentFactory.BuildSegment(
                async,
                segments.Dequeue(),
                cursor?.CurrentSegmentCursor)
                                     .ConfigureAwait(false);

            return(new ChangeFeed(
                       _containerClient,
                       _segmentFactory,
                       years,
                       segments,
                       currentSegment,
                       lastConsumable,
                       startTime,
                       endTime));
        }