Exemplo n.º 1
0
        public void GivenEmptyInput_WhenGettingProgress_ThenReturnDefaultStatus()
        {
            OperationProgress progress = new ReindexInput().GetProgress();

            Assert.Equal(0, progress.PercentComplete);
            Assert.Null(progress.ResourceIds);
        }
 public virtual async Task ReindexAsync(ReindexInput input)
 {
     await RequestAsync(nameof(ReindexAsync), new ClientProxyRequestTypeValue
     {
         { typeof(ReindexInput), input }
     });
 }
Exemplo n.º 3
0
        public void GivenMinimumCompletion_WhenGettingProgress_ThenReturnCompletedProgress()
        {
            OperationProgress progress = new ReindexInput {
                Completed = new WatermarkRange(1, 1)
            }.GetProgress();

            Assert.Equal(100, progress.PercentComplete);
            Assert.Null(progress.ResourceIds);
        }
        private static OperationProgress GetOperationProgress(OperationType type, DurableOrchestrationStatus status)
        {
            switch (type)
            {
            case OperationType.Reindex:
                ReindexInput reindexInput = status.Input?.ToObject <ReindexInput>() ?? new ReindexInput();
                return(reindexInput.GetProgress());

            default:
                return(new OperationProgress());
            }
        }
Exemplo n.º 5
0
        public void GivenReindexInput_WhenGettingProgress_ThenReturnComputedProgress(int start, int end, int expected)
        {
            int[] expectedTagKeys = new int[] { 1, 3, 10 };

            OperationProgress progress = new ReindexInput
            {
                Completed    = new WatermarkRange(start, end),
                QueryTagKeys = expectedTagKeys,
            }.GetProgress();

            Assert.Equal(expected, progress.PercentComplete);
            Assert.True(progress.ResourceIds.SequenceEqual(expectedTagKeys.Select(x => x.ToString(CultureInfo.InvariantCulture))));
        }
        public async Task ReindexInstancesAsync(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger logger)
        {
            EnsureArg.IsNotNull(context, nameof(context));

            logger = context.CreateReplaySafeLogger(logger);
            ReindexInput input = context.GetInput <ReindexInput>();

            // The ID should be a GUID as generated by the trigger, but we'll assert here just to make sure!
            if (!context.HasInstanceGuid())
            {
                return;
            }

            // Fetch the set of query tags that require re-indexing
            IReadOnlyList <ExtendedQueryTagStoreEntry> queryTags = await GetOperationQueryTagsAsync(context, input);

            logger.LogInformation(
                "Found {Count} extended query tag paths to re-index {{{TagPaths}}}.",
                queryTags.Count,
                string.Join(", ", queryTags.Select(x => x.Path)));

            List <int> queryTagKeys = queryTags.Select(x => x.Key).ToList();

            if (queryTags.Count > 0)
            {
                IReadOnlyList <WatermarkRange> batches = await context.CallActivityWithRetryAsync <IReadOnlyList <WatermarkRange> >(
                    nameof(GetInstanceBatchesV2Async),
                    _options.ActivityRetryOptions,
                    BatchCreationArguments.FromOptions(input.Completed?.Start - 1, _options));

                if (batches.Count > 0)
                {
                    // Note that batches are in reverse order because we start from the highest watermark
                    var batchRange = new WatermarkRange(batches[^ 1].Start, batches[0].End);
Exemplo n.º 7
0
 public Task ReindexAsync(ReindexInput input)
 {
     return(_projectAppService.ReindexAsync(input));
 }
        public async Task GivenNewOrchestrationWithWork_WhenReindexingInstances_ThenDivideAndReindexBatches()
        {
            const int batchSize = 5;

            _options.BatchSize          = batchSize;
            _options.MaxParallelBatches = 3;

            IReadOnlyList <WatermarkRange> expectedBatches = CreateBatches(50);
            var expectedInput = new ReindexInput {
                QueryTagKeys = new List <int> {
                    1, 2, 3, 4, 5
                }
            };
            var expectedTags = new List <ExtendedQueryTagStoreEntry>
            {
                new ExtendedQueryTagStoreEntry(1, "01010101", "AS", null, QueryTagLevel.Instance, ExtendedQueryTagStatus.Adding, QueryStatus.Enabled, 0),
                new ExtendedQueryTagStoreEntry(2, "02020202", "IS", "foo", QueryTagLevel.Series, ExtendedQueryTagStatus.Adding, QueryStatus.Enabled, 0),
                new ExtendedQueryTagStoreEntry(4, "04040404", "SH", null, QueryTagLevel.Study, ExtendedQueryTagStatus.Adding, QueryStatus.Enabled, 0)
            };

            // Arrange the input
            IDurableOrchestrationContext context = CreateContext();

            context
            .GetInput <ReindexInput>()
            .Returns(expectedInput);
            context
            .CallActivityWithRetryAsync <IReadOnlyList <ExtendedQueryTagStoreEntry> >(
                nameof(ReindexDurableFunction.AssignReindexingOperationAsync),
                _options.ActivityRetryOptions,
                expectedInput.QueryTagKeys)
            .Returns(expectedTags);
            context
            .CallActivityWithRetryAsync <IReadOnlyList <WatermarkRange> >(
                nameof(ReindexDurableFunction.GetInstanceBatchesV2Async),
                _options.ActivityRetryOptions,
                Arg.Is(GetPredicate(null)))
            .Returns(expectedBatches);
            context
            .CallActivityWithRetryAsync(
                nameof(ReindexDurableFunction.ReindexBatchV2Async),
                _options.ActivityRetryOptions,
                Arg.Any <ReindexBatchArguments>())
            .Returns(Task.CompletedTask);

            // Invoke the orchestration
            await _reindexDurableFunction.ReindexInstancesAsync(context, NullLogger.Instance);

            // Assert behavior
            context
            .Received(1)
            .GetInput <ReindexInput>();
            await context
            .Received(1)
            .CallActivityWithRetryAsync <IReadOnlyList <ExtendedQueryTagStoreEntry> >(
                nameof(ReindexDurableFunction.AssignReindexingOperationAsync),
                _options.ActivityRetryOptions,
                expectedInput.QueryTagKeys);

            await context
            .DidNotReceive()
            .CallActivityWithRetryAsync <IReadOnlyList <ExtendedQueryTagStoreEntry> >(
                nameof(ReindexDurableFunction.GetQueryTagsAsync),
                _options.ActivityRetryOptions,
                Arg.Any <object>());

            await context
            .Received(1)
            .CallActivityWithRetryAsync <IReadOnlyList <WatermarkRange> >(
                nameof(ReindexDurableFunction.GetInstanceBatchesV2Async),
                _options.ActivityRetryOptions,
                Arg.Is(GetPredicate(null)));

            foreach (WatermarkRange batch in expectedBatches)
            {
                await context
                .Received(1)
                .CallActivityWithRetryAsync(
                    nameof(ReindexDurableFunction.ReindexBatchV2Async),
                    _options.ActivityRetryOptions,
                    Arg.Is(GetPredicate(expectedTags, batch)));
            }

            await context
            .DidNotReceive()
            .CallActivityWithRetryAsync <IReadOnlyList <int> >(
                nameof(ReindexDurableFunction.CompleteReindexingAsync),
                _options.ActivityRetryOptions,
                Arg.Any <object>());

            context
            .Received(1)
            .ContinueAsNew(
                Arg.Is <ReindexInput>(x => GetPredicate(expectedTags, expectedBatches, 50)(x)),
                false);
        }
        public async Task GivenNoInstances_WhenReindexingInstances_ThenComplete()
        {
            var expectedBatches = new List <WatermarkRange>();
            var expectedInput   = new ReindexInput {
                QueryTagKeys = new List <int> {
                    1, 2, 3, 4, 5
                }
            };
            var expectedTags = new List <ExtendedQueryTagStoreEntry>
            {
                new ExtendedQueryTagStoreEntry(1, "01010101", "AS", null, QueryTagLevel.Instance, ExtendedQueryTagStatus.Adding, QueryStatus.Enabled, 0),
                new ExtendedQueryTagStoreEntry(2, "02020202", "IS", "foo", QueryTagLevel.Series, ExtendedQueryTagStatus.Adding, QueryStatus.Enabled, 0),
                new ExtendedQueryTagStoreEntry(4, "04040404", "SH", null, QueryTagLevel.Study, ExtendedQueryTagStatus.Adding, QueryStatus.Enabled, 0)
            };

            // Arrange the input
            IDurableOrchestrationContext context = CreateContext();

            context
            .GetInput <ReindexInput>()
            .Returns(expectedInput);
            context
            .CallActivityWithRetryAsync <IReadOnlyList <ExtendedQueryTagStoreEntry> >(
                nameof(ReindexDurableFunction.AssignReindexingOperationAsync),
                _options.ActivityRetryOptions,
                expectedInput.QueryTagKeys)
            .Returns(expectedTags);
            context
            .CallActivityWithRetryAsync <IReadOnlyList <WatermarkRange> >(
                nameof(ReindexDurableFunction.GetInstanceBatchesV2Async),
                _options.ActivityRetryOptions,
                Arg.Is(GetPredicate(null)))
            .Returns(expectedBatches);
            context
            .CallActivityWithRetryAsync <IReadOnlyList <int> >(
                nameof(ReindexDurableFunction.CompleteReindexingAsync),
                _options.ActivityRetryOptions,
                Arg.Is <IReadOnlyList <int> >(x => x.SequenceEqual(expectedTags.Select(x => x.Key))))
            .Returns(expectedTags.Select(x => x.Key).ToList());

            // Invoke the orchestration
            await _reindexDurableFunction.ReindexInstancesAsync(context, NullLogger.Instance);

            // Assert behavior
            context
            .Received(1)
            .GetInput <ReindexInput>();
            await context
            .Received(1)
            .CallActivityWithRetryAsync <IReadOnlyList <ExtendedQueryTagStoreEntry> >(
                nameof(ReindexDurableFunction.AssignReindexingOperationAsync),
                _options.ActivityRetryOptions,
                expectedInput.QueryTagKeys);

            await context
            .DidNotReceive()
            .CallActivityWithRetryAsync <IReadOnlyList <ExtendedQueryTagStoreEntry> >(
                nameof(ReindexDurableFunction.GetQueryTagsAsync),
                _options.ActivityRetryOptions,
                Arg.Any <object>());

            await context
            .Received(1)
            .CallActivityWithRetryAsync <IReadOnlyList <WatermarkRange> >(
                nameof(ReindexDurableFunction.GetInstanceBatchesV2Async),
                _options.ActivityRetryOptions,
                Arg.Is(GetPredicate(null)));

            await context
            .DidNotReceive()
            .CallActivityWithRetryAsync(
                nameof(ReindexDurableFunction.ReindexBatchV2Async),
                _options.ActivityRetryOptions,
                Arg.Any <object>());

            await context
            .Received(1)
            .CallActivityWithRetryAsync <IReadOnlyList <int> >(
                nameof(ReindexDurableFunction.CompleteReindexingAsync),
                _options.ActivityRetryOptions,
                Arg.Is <IReadOnlyList <int> >(x => x.SequenceEqual(expectedTags.Select(x => x.Key))));

            context
            .DidNotReceiveWithAnyArgs()
            .ContinueAsNew(default, default);