public async Task DoesNotEmitTelemetryIfMultipleValidationSetsExist()
        {
            const string validation1 = "validation1";

            Configuration.Validations = new List <ValidationConfigurationItem>
            {
                new ValidationConfigurationItem()
                {
                    Name = validation1, TrackAfter = TimeSpan.FromDays(1), RequiredValidations = new List <string> {
                    }
                }
            };

            Guid validationTrackingId = Guid.NewGuid();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetAsync(validationTrackingId))
            .ReturnsAsync((PackageValidationSet)null)
            .Verifiable();

            PackageValidationSet createdSet = null;

            ValidationStorageMock
            .Setup(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()))
            .Returns <PackageValidationSet>(pvs => Task.FromResult(pvs))
            .Callback <PackageValidationSet>(pvs => createdSet = pvs)
            .Verifiable();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetCountAsync(It.IsAny <IValidatingEntity <Package> >()))
            .ReturnsAsync(2);

            ValidationStorageMock
            .Setup(vs => vs.OtherRecentValidationSetForPackageExists(It.IsAny <IValidatingEntity <Package> >(), It.IsAny <TimeSpan>(), It.IsAny <Guid>()))
            .ReturnsAsync(false);

            var provider = new ValidationSetProvider <Package>(
                ValidationStorageMock.Object,
                PackageFileServiceMock.Object,
                ValidatorProvider.Object,
                ConfigurationAccessorMock.Object,
                TelemetryServiceMock.Object,
                LoggerMock.Object);

            var packageValidationMessageData = new ProcessValidationSetData(
                Package.PackageRegistration.Id,
                Package.NormalizedVersion,
                validationTrackingId,
                ValidatingType.Package,
                Package.Key);

            var returnedSet = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity);

            ValidationStorageMock
            .Verify(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Once);

            TelemetryServiceMock.Verify(
                x => x.TrackDurationToValidationSetCreation(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Guid>(), It.IsAny <TimeSpan>()),
                Times.Never);
        }
        public async Task CopiesPackageFromValidationContainerWhenNotAvailable(PackageStatus packageStatus)
        {
            const string validation1 = "validation1";

            Configuration.Validations = new List <ValidationConfigurationItem>
            {
                new ValidationConfigurationItem()
                {
                    Name                = validation1,
                    TrackAfter          = TimeSpan.FromDays(1),
                    RequiredValidations = new List <string>(),
                    ShouldStart         = true,
                }
            };

            Package.PackageStatusKey = packageStatus;

            Guid validationTrackingId = Guid.NewGuid();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetAsync(validationTrackingId))
            .ReturnsAsync((PackageValidationSet)null)
            .Verifiable();

            ValidationStorageMock
            .Setup(vs => vs.OtherRecentValidationSetForPackageExists(It.IsAny <IValidatingEntity <Package> >(), It.IsAny <TimeSpan>(), validationTrackingId))
            .ReturnsAsync(false);

            PackageValidationSet createdSet = null;

            ValidationStorageMock
            .Setup(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()))
            .Returns <PackageValidationSet>(pvs => Task.FromResult(pvs))
            .Callback <PackageValidationSet>(pvs => createdSet = pvs)
            .Verifiable();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetCountAsync(It.IsAny <IValidatingEntity <Package> >()))
            .ReturnsAsync(1);

            var provider = CreateProvider();

            var packageValidationMessageData = new ProcessValidationSetData(
                Package.PackageRegistration.Id,
                Package.NormalizedVersion,
                validationTrackingId,
                ValidatingType.Package,
                Package.Key);
            var actual = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity);

            PackageFileServiceMock.Verify(x => x.CopyPackageFileForValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Never);
            PackageFileServiceMock.Verify(x => x.CopyValidationPackageForValidationSetAsync(createdSet), Times.Once);
            PackageFileServiceMock.Verify(x => x.CopyValidationPackageForValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Once);
            PackageFileServiceMock.Verify(x => x.BackupPackageFileFromValidationSetPackageAsync(createdSet), Times.Once);
            Assert.Null(actual.PackageETag);
        }
        public async Task DoesNotBackUpThePackageWhenThereAreNoValidators()
        {
            const string validation1 = "validation1";

            Configuration.Validations = new List <ValidationConfigurationItem>
            {
                new ValidationConfigurationItem()
                {
                    Name = validation1, TrackAfter = TimeSpan.FromDays(1), RequiredValidations = new List <string> {
                    }
                }
            };

            ValidatorProvider
            .Setup(x => x.IsNuGetProcessor(validation1))
            .Returns(false);

            Guid validationTrackingId = Guid.NewGuid();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetAsync(validationTrackingId))
            .ReturnsAsync((PackageValidationSet)null)
            .Verifiable();

            ValidationStorageMock
            .Setup(vs => vs.OtherRecentValidationSetForPackageExists(It.IsAny <IValidatingEntity <Package> >(), It.IsAny <TimeSpan>(), validationTrackingId))
            .ReturnsAsync(false);

            PackageValidationSet createdSet = null;

            ValidationStorageMock
            .Setup(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()))
            .Returns <PackageValidationSet>(pvs => Task.FromResult(pvs))
            .Callback <PackageValidationSet>(pvs => createdSet = pvs)
            .Verifiable();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetCountAsync(It.IsAny <IValidatingEntity <Package> >()))
            .ReturnsAsync(1);

            var provider = CreateProvider();

            var packageValidationMessageData = new ProcessValidationSetData(
                Package.PackageRegistration.Id,
                Package.NormalizedVersion,
                validationTrackingId,
                ValidatingType.Package,
                Package.Key);
            var actual = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity);

            PackageFileServiceMock.Verify(
                x => x.BackupPackageFileFromValidationSetPackageAsync(It.IsAny <PackageValidationSet>()),
                Times.Never);
        }
        private PackageValidationSet InitializeValidationSet(ProcessValidationSetData message, IValidatingEntity <T> validatingEntity)
        {
            // If message would have the package Key the package will not need to be passed as an argument
            _logger.LogInformation("Initializing validation set {ValidationSetId} for package {PackageId} {PackageVersion} (package key {PackageKey})",
                                   message.ValidationTrackingId,
                                   message.PackageId,
                                   message.PackageVersion,
                                   validatingEntity.Key);

            var now = DateTime.UtcNow;

            var validationSet = new PackageValidationSet
            {
                Created   = now,
                PackageId = message.PackageId,
                PackageNormalizedVersion = message.PackageNormalizedVersion,
                PackageKey           = validatingEntity.Key,
                PackageValidations   = new List <PackageValidation>(),
                Updated              = now,
                ValidationTrackingId = message.ValidationTrackingId,
                ValidatingType       = message.ValidatingType,
                ValidationSetStatus  = ValidationSetStatus.InProgress,
            };

            var validationsToStart = _validationConfiguration
                                     .Validations
                                     .Where(v => v.ShouldStart);

            foreach (var validation in validationsToStart)
            {
                var packageValidation = new PackageValidation
                {
                    PackageValidationSet = validationSet,
                    ValidationStatus     = ValidationStatus.NotStarted,
                    Type = validation.Name,
                    ValidationStatusTimestamp = now,
                };

                validationSet.PackageValidations.Add(packageValidation);
            }

            return(validationSet);
        }
        public async Task GetOrCreateValidationSetAsyncDoesNotCreateDuplicateValidationSet()
        {
            Guid validationTrackingId = Guid.NewGuid();
            var  message = new ProcessValidationSetData(
                PackageValidationMessageData.PackageId,
                PackageValidationMessageData.PackageVersion,
                validationTrackingId,
                ValidatingType.Package,
                PackageValidationMessageData.EntityKey);

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetAsync(validationTrackingId))
            .ReturnsAsync((PackageValidationSet)null);

            ValidationStorageMock
            .Setup(vs => vs.OtherRecentValidationSetForPackageExists(
                       PackageValidatingEntity,
                       It.IsAny <TimeSpan>(),
                       validationTrackingId))
            .ReturnsAsync(true);

            var provider = CreateProvider();
            var result   = await provider.TryGetOrCreateValidationSetAsync(message, PackageValidatingEntity);

            Assert.Null(result);
            ValidationStorageMock
            .Verify(
                vs => vs.OtherRecentValidationSetForPackageExists(
                    PackageValidatingEntity,
                    It.IsAny <TimeSpan>(),
                    validationTrackingId),
                Times.Once);
            ValidationStorageMock
            .Verify(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Never);
            PackageFileServiceMock.Verify(
                x => x.CopyPackageFileForValidationSetAsync(It.IsAny <PackageValidationSet>()),
                Times.Never);
            PackageFileServiceMock.Verify(
                x => x.CopyValidationPackageForValidationSetAsync(It.IsAny <PackageValidationSet>()),
                Times.Never);
        }
        public async Task CopiesToValidationSetContainerBeforeAddingDbRecord()
        {
            const string validation1 = "validation1";

            Configuration.Validations = new List <ValidationConfigurationItem>
            {
                new ValidationConfigurationItem
                {
                    Name                = validation1,
                    TrackAfter          = TimeSpan.FromDays(1),
                    RequiredValidations = new List <string>(),
                    ShouldStart         = true,
                }
            };

            Package.PackageStatusKey = PackageStatus.Available;

            var operations = new List <string>();

            Guid validationTrackingId = Guid.NewGuid();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetAsync(validationTrackingId))
            .ReturnsAsync((PackageValidationSet)null)
            .Verifiable();

            ValidationStorageMock
            .Setup(vs => vs.OtherRecentValidationSetForPackageExists(It.IsAny <IValidatingEntity <Package> >(), It.IsAny <TimeSpan>(), validationTrackingId))
            .ReturnsAsync(false);

            PackageFileServiceMock
            .Setup(x => x.CopyPackageFileForValidationSetAsync(It.IsAny <PackageValidationSet>()))
            .ReturnsAsync(ETag)
            .Callback <PackageValidationSet>(_ => operations.Add(nameof(IValidationFileService.CopyPackageFileForValidationSetAsync)));
            PackageFileServiceMock
            .Setup(x => x.BackupPackageFileFromValidationSetPackageAsync(It.IsAny <PackageValidationSet>()))
            .Returns(Task.CompletedTask)
            .Callback(() => operations.Add(nameof(IValidationFileService.BackupPackageFileFromValidationSetPackageAsync)));
            ValidationStorageMock
            .Setup(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()))
            .Returns <PackageValidationSet>(pvs => Task.FromResult(pvs))
            .Callback <PackageValidationSet>(_ => operations.Add(nameof(IValidationStorageService.CreateValidationSetAsync)));

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetCountAsync(It.IsAny <IValidatingEntity <Package> >()))
            .ReturnsAsync(1);

            var provider = CreateProvider();
            var packageValidationMessageData = new ProcessValidationSetData(
                Package.PackageRegistration.Id,
                Package.NormalizedVersion,
                validationTrackingId,
                ValidatingType.Package,
                Package.Key);
            await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, new PackageValidatingEntity(Package));

            Assert.Equal(new[]
            {
                nameof(IValidationFileService.CopyPackageFileForValidationSetAsync),
                nameof(IValidationFileService.BackupPackageFileFromValidationSetPackageAsync),
                nameof(IValidationStorageService.CreateValidationSetAsync),
            }, operations);
        }
        public ValidationSetProviderFacts()
        {
            ValidationStorageMock     = new Mock <IValidationStorageService>(MockBehavior.Strict);
            PackageFileServiceMock    = new Mock <IValidationFileService>(MockBehavior.Strict);
            ValidatorProvider         = new Mock <IValidatorProvider>(MockBehavior.Strict);
            ConfigurationAccessorMock = new Mock <IOptionsSnapshot <ValidationConfiguration> >();
            TelemetryServiceMock      = new Mock <ITelemetryService>();
            LoggerMock = new Mock <ILogger <ValidationSetProvider <Package> > >();

            PackageFileServiceMock
            .Setup(x => x.CopyPackageFileForValidationSetAsync(It.IsAny <PackageValidationSet>()))
            .ReturnsAsync(() => ETag);

            PackageFileServiceMock
            .Setup(x => x.CopyValidationPackageForValidationSetAsync(It.IsAny <PackageValidationSet>()))
            .Returns(Task.CompletedTask);

            PackageFileServiceMock
            .Setup(x => x.BackupPackageFileFromValidationSetPackageAsync(It.IsAny <PackageValidationSet>()))
            .Returns(Task.CompletedTask);

            ValidatorProvider
            .Setup(x => x.IsNuGetProcessor(It.IsAny <string>()))
            .Returns(true);

            Configuration = new ValidationConfiguration();
            ConfigurationAccessorMock
            .SetupGet(ca => ca.Value)
            .Returns(() => Configuration);

            ETag    = "\"some-etag\"";
            Package = new Package
            {
                PackageRegistration = new PackageRegistration {
                    Id = "package1"
                },
                Version           = "1.2.3.456",
                NormalizedVersion = "1.2.3",
                Key              = 42,
                Created          = new DateTime(2010, 1, 2, 8, 30, 0, DateTimeKind.Utc),
                PackageStatusKey = PackageStatus.Validating,
            };
            Package.PackageRegistration.Packages = new List <Package> {
                Package
            };

            ValidationSet = new PackageValidationSet
            {
                PackageId = Package.PackageRegistration.Id,
                PackageNormalizedVersion = Package.NormalizedVersion,
                PackageKey           = Package.Key,
                ValidationTrackingId = Guid.NewGuid(),
            };

            PackageValidationMessageData = new ProcessValidationSetData(
                Package.PackageRegistration.Id,
                Package.NormalizedVersion,
                ValidationSet.ValidationTrackingId,
                ValidatingType.Package,
                Package.Key);

            PackageValidatingEntity = new PackageValidatingEntity(Package);
        }
        public async Task DoesNotCreateValidationsWhenShouldStartFalse()
        {
            const string validation1 = "validation1";
            const string validation2 = "validation2";

            Configuration.Validations = new List <ValidationConfigurationItem>
            {
                new ValidationConfigurationItem()
                {
                    Name                = validation1,
                    TrackAfter          = TimeSpan.FromDays(1),
                    RequiredValidations = new List <string>(),
                    ShouldStart         = true,
                },
                new ValidationConfigurationItem()
                {
                    Name                = validation2,
                    TrackAfter          = TimeSpan.FromDays(1),
                    RequiredValidations = new List <string>(),
                    ShouldStart         = false,
                }
            };

            Guid validationTrackingId = Guid.NewGuid();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetAsync(validationTrackingId))
            .ReturnsAsync((PackageValidationSet)null)
            .Verifiable();

            ValidationStorageMock
            .Setup(vs => vs.OtherRecentValidationSetForPackageExists(It.IsAny <IValidatingEntity <Package> >(), It.IsAny <TimeSpan>(), validationTrackingId))
            .ReturnsAsync(false);

            PackageValidationSet createdSet = null;

            ValidationStorageMock
            .Setup(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()))
            .Returns <PackageValidationSet>(pvs => Task.FromResult(pvs))
            .Callback <PackageValidationSet>(pvs => createdSet = pvs)
            .Verifiable();

            ValidationStorageMock
            .Setup(vs => vs.GetValidationSetCountAsync(It.IsAny <IValidatingEntity <Package> >()))
            .ReturnsAsync(1);

            var provider = new ValidationSetProvider <Package>(
                ValidationStorageMock.Object,
                PackageFileServiceMock.Object,
                ValidatorProvider.Object,
                ConfigurationAccessorMock.Object,
                TelemetryServiceMock.Object,
                LoggerMock.Object);

            var packageValidationMessageData = new ProcessValidationSetData(
                Package.PackageRegistration.Id,
                Package.NormalizedVersion,
                validationTrackingId,
                ValidatingType.Package,
                Package.Key);
            var returnedSet = await provider.TryGetOrCreateValidationSetAsync(packageValidationMessageData, PackageValidatingEntity);

            var endOfCallTimestamp = DateTime.UtcNow;

            ValidationStorageMock
            .Verify(vs => vs.CreateValidationSetAsync(It.IsAny <PackageValidationSet>()), Times.Once);

            Assert.NotNull(returnedSet);
            Assert.NotNull(createdSet);
            Assert.Same(createdSet, returnedSet);
            Assert.Equal(Package.PackageRegistration.Id, createdSet.PackageId);
            Assert.Equal(Package.NormalizedVersion, createdSet.PackageNormalizedVersion);
            Assert.Equal(Package.Key, createdSet.PackageKey);
            Assert.Equal(validationTrackingId, createdSet.ValidationTrackingId);
            Assert.True(createdSet.Created.Kind == DateTimeKind.Utc);
            Assert.True(createdSet.Updated.Kind == DateTimeKind.Utc);

            var allowedTimeDifference = TimeSpan.FromSeconds(5);

            Assert.True(endOfCallTimestamp - createdSet.Created < allowedTimeDifference);
            Assert.True(endOfCallTimestamp - createdSet.Updated < allowedTimeDifference);
            Assert.All(createdSet.PackageValidations, v => Assert.Same(createdSet, v.PackageValidationSet));
            Assert.All(createdSet.PackageValidations, v => Assert.Equal(ValidationStatus.NotStarted, v.ValidationStatus));
            Assert.All(createdSet.PackageValidations, v => Assert.True(endOfCallTimestamp - v.ValidationStatusTimestamp < allowedTimeDifference));
            Assert.Contains(createdSet.PackageValidations, v => v.Type == validation1);
            Assert.DoesNotContain(createdSet.PackageValidations, v => v.Type == validation2);

            PackageFileServiceMock.Verify(
                x => x.CopyValidationPackageForValidationSetAsync(returnedSet),
                Times.Once);
            TelemetryServiceMock.Verify(
                x => x.TrackDurationToValidationSetCreation(createdSet.PackageId, createdSet.PackageNormalizedVersion, createdSet.ValidationTrackingId, createdSet.Created - Package.Created),
                Times.Once);
        }
        public async Task <PackageValidationSet> TryGetOrCreateValidationSetAsync(ProcessValidationSetData message, IValidatingEntity <T> validatingEntity)
        {
            var validationSet = await _validationStorageService.GetValidationSetAsync(message.ValidationTrackingId);

            if (validationSet == null)
            {
                var shouldSkip = await _validationStorageService.OtherRecentValidationSetForPackageExists(
                    validatingEntity,
                    _validationConfiguration.NewValidationRequestDeduplicationWindow,
                    message.ValidationTrackingId);

                if (shouldSkip)
                {
                    return(null);
                }

                validationSet = InitializeValidationSet(message, validatingEntity);

                if (validatingEntity.Status == PackageStatus.Available)
                {
                    var packageETag = await _packageFileService.CopyPackageFileForValidationSetAsync(validationSet);

                    // This indicates that the package in the package container is expected to not change.
                    validationSet.PackageETag = packageETag;
                }
                else
                {
                    await _packageFileService.CopyValidationPackageForValidationSetAsync(validationSet);

                    // A symbols package for the same id and version can be re-submitted.
                    // When this happens a new validation is submitted. After validation the new symbols package will overwrite the old symbols package.
                    // Because of this when a new validation for a symbols package is received it can already exist a symbols package in the public symbols container.
                    if (validatingEntity.ValidatingType == ValidatingType.SymbolPackage)
                    {
                        validationSet.PackageETag = await _packageFileService.GetPublicPackageBlobETagOrNullAsync(validationSet);
                    }
                    else
                    {
                        // This indicates that the package in the packages container is expected to not exist (i.e. it has
                        // has no etag at all).
                        validationSet.PackageETag = null;
                    }
                }

                // If there are any processors in the validation set, back up the original. We back up from the
                // validation set copy to avoid concurrency issues.
                if (validationSet.PackageValidations.Any(x => _validatorProvider.IsNuGetProcessor(x.Type)))
                {
                    await _packageFileService.BackupPackageFileFromValidationSetPackageAsync(validationSet, _sasDefinitionConfiguration.ValidationSetProviderSasDefinition);
                }

                validationSet = await PersistValidationSetAsync(validationSet, validatingEntity);
            }
            else
            {
                var sameKey = validatingEntity.Key == validationSet.PackageKey;

                if (!sameKey)
                {
                    throw new InvalidOperationException($"Validation set  key ({validationSet.PackageKey}) " +
                                                        $"does not match expected {validatingEntity.EntityRecord.GetType().Name} key ({validatingEntity.Key}).");
                }
            }

            return(validationSet);
        }
示例#10
0
        private async Task <bool> ProcessValidationSetAsync(ProcessValidationSetData message, int deliveryCount)
        {
            using (_logger.BeginScope(
                       "Handling process validation set message for {ValidatingType} {PackageId} {PackageVersion} {Key} " +
                       "{ValidationSetId}",
                       ValidatingType,
                       message.PackageId,
                       message.PackageNormalizedVersion,
                       message.EntityKey,
                       message.ValidationTrackingId))
            {
                // When a message is sent from the Gallery with validation of a new entity, the EntityKey will be null
                // because the message is sent to the service bus before the entity is persisted in the DB. However
                // when a revalidation happens or when the message is re-sent by the orchestrator the message will
                // contain the key. In this case the key is used to find the entity to validate.
                var entity = message.EntityKey.HasValue
                    ? _entityService.FindPackageByKey(message.EntityKey.Value)
                    : _entityService.FindPackageByIdAndVersionStrict(message.PackageId, message.PackageNormalizedVersion);

                if (entity == null)
                {
                    // no package in DB yet. Might have received message a bit early, need to retry later
                    if (deliveryCount - 1 >= _configs.MissingPackageRetryCount)
                    {
                        _logger.LogWarning(
                            "Could not find {ValidatingType} {PackageId} {PackageVersion} {Key} in DB after " +
                            "{DeliveryCount} tries. Discarding the message.",
                            ValidatingType,
                            message.PackageId,
                            message.PackageNormalizedVersion,
                            message.EntityKey,
                            deliveryCount);

                        _telemetryService.TrackMissingPackageForValidationMessage(
                            message.PackageId,
                            message.PackageNormalizedVersion,
                            message.ValidationTrackingId.ToString());

                        return(true);
                    }
                    else
                    {
                        _logger.LogInformation(
                            "Could not find {ValidatingType} {PackageId} {PackageVersion} {Key} in DB. Retrying.",
                            ValidatingType,
                            message.PackageId,
                            message.PackageNormalizedVersion,
                            message.EntityKey);

                        return(false);
                    }
                }

                // Immediately halt validation of a soft deleted package.
                if (ShouldNoOpDueToDeletion && entity.Status == PackageStatus.Deleted)
                {
                    _logger.LogWarning(
                        "{ValidatingType} {PackageId} {PackageNormalizedVersion} {Key} is soft deleted. Dropping " +
                        "message for validation set {ValidationSetId}.",
                        ValidatingType,
                        message.PackageId,
                        message.PackageNormalizedVersion,
                        entity.Key,
                        message.ValidationTrackingId);

                    return(true);
                }

                var lease = await TryAcquireLeaseAsync(message.PackageId, message.PackageNormalizedVersion);

                if (lease.State == LeaseContextState.Unavailable)
                {
                    _logger.LogInformation(
                        "The lease {ResourceName} is unavailable. Retrying this message in {LeaseTime}.",
                        lease.ResourceName,
                        LeaseTime);
                    var messageData = PackageValidationMessageData.NewProcessValidationSet(
                        message.PackageId,
                        message.PackageNormalizedVersion,
                        message.ValidationTrackingId,
                        message.ValidatingType,
                        message.EntityKey);
                    var postponeUntil = DateTimeOffset.UtcNow + LeaseTime;
                    await _validationEnqueuer.SendMessageAsync(messageData, postponeUntil);

                    return(true);
                }

                try
                {
                    var validationSet = await _validationSetProvider.TryGetOrCreateValidationSetAsync(message, entity);

                    if (validationSet == null)
                    {
                        _logger.LogInformation(
                            "The validation request for {ValidatingType} {PackageId} {PackageVersion} {Key} " +
                            "{ValidationSetId} is a duplicate. Discarding the message.",
                            ValidatingType,
                            message.PackageId,
                            message.PackageNormalizedVersion,
                            entity.Key,
                            message.ValidationTrackingId);
                        return(true);
                    }

                    await ProcessValidationSetAsync(entity, validationSet, scheduleNextCheck : true);
                }
                finally
                {
                    await TryReleaseLeaseAsync(lease);
                }
            }

            return(true);
        }