private async Task <StartRevalidationResult> StartRevalidationsAsync(IReadOnlyList <PackageRevalidation> revalidations) { _logger.LogInformation("Starting {RevalidationCount} revalidations...", revalidations.Count); foreach (var revalidation in revalidations) { _logger.LogInformation( "Starting revalidation for package {PackageId} {PackageVersion}...", revalidation.PackageId, revalidation.PackageNormalizedVersion); var message = PackageValidationMessageData.NewProcessValidationSet( revalidation.PackageId, revalidation.PackageNormalizedVersion, revalidation.ValidationTrackingId.Value, ValidatingType.Package, entityKey: null); await _validationEnqueuer.SendMessageAsync(message); _telemetryService.TrackPackageRevalidationStarted(revalidation.PackageId, revalidation.PackageNormalizedVersion); _logger.LogInformation( "Started revalidation for package {PackageId} {PackageVersion}", revalidation.PackageId, revalidation.PackageNormalizedVersion); } _logger.LogInformation("Started {RevalidationCount} revalidations, marking them as enqueued...", revalidations.Count); await _packageState.MarkPackageRevalidationsAsEnqueuedAsync(revalidations); _logger.LogInformation("Marked {RevalidationCount} revalidations as enqueued", revalidations.Count); return(StartRevalidationResult.RevalidationsEnqueued(revalidations.Count)); }
public async Task <PackageStatus> StartValidationAsync(TPackageEntity package) { var validatingType = ValidateAndGetType(package); var entityKey = package.Key == default(int) ? (int?)null : package.Key; var data = PackageValidationMessageData.NewProcessValidationSet( package.Id, package.Version, Guid.NewGuid(), validatingType, entityKey: entityKey); var activityName = $"Enqueuing asynchronous package validation: " + $"{data.ProcessValidationSet.PackageId} {data.ProcessValidationSet.PackageVersion} " + $"{data.ProcessValidationSet.ValidatingType} ({data.ProcessValidationSet.ValidationTrackingId})"; using (_diagnosticsSource.Activity(activityName)) { var postponeProcessingTill = DateTimeOffset.UtcNow + _appConfiguration.AsynchronousPackageValidationDelay; await _validationEnqueuer.SendMessageAsync(data, postponeProcessingTill); } return(TargetPackageStatus); }
private async Task ScheduleCheckIfNotTimedOut( PackageValidationSet validationSet, IValidatingEntity <T> validatingEntity, bool scheduleNextCheck, bool tooLongNotificationAllowed) { var validationSetDuration = await UpdateValidationDurationAsync(validationSet, validatingEntity, tooLongNotificationAllowed); // Schedule another check if we haven't reached the validation set timeout yet. if (validationSetDuration <= _validationConfiguration.TimeoutValidationSetAfter) { if (scheduleNextCheck) { var messageData = PackageValidationMessageData.NewProcessValidationSet( validationSet.PackageId, validationSet.PackageNormalizedVersion, validationSet.ValidationTrackingId, validationSet.ValidatingType, entityKey: validationSet.PackageKey); var postponeUntil = DateTimeOffset.UtcNow + _validationConfiguration.ValidationMessageRecheckPeriod; await _validationEnqueuer.SendMessageAsync(messageData, postponeUntil); } } else { _logger.LogWarning("Abandoning checking status of validation set {ValidationTrackingId} for " + "package {PackageId} {PackageVersion} because it took too long (Duration: {Duration}, CutOffDuration: {CutOffDuration})", validationSet.ValidationTrackingId, validationSet.PackageId, validationSet.PackageNormalizedVersion, validationSetDuration, _validationConfiguration.TimeoutValidationSetAfter); _telemetryService.TrackValidationSetTimeout(validationSet.PackageId, validationSet.PackageNormalizedVersion, validationSet.ValidationTrackingId); } }
private async Task <bool> HandleAsync(SignatureValidationMessage message, CancellationToken cancellationToken) { using (_logger.BeginScope("Handling signature validation message for package {PackageId} {PackageVersion}, validation {ValidationId}", message.PackageId, message.PackageVersion, message.ValidationId)) { // Find the signature validation entity that matches this message. var validation = await _validatorStateService.GetStatusAsync(message.ValidationId); // A signature validation should be queued with ValidatorState == Incomplete. if (validation == null) { _logger.LogInformation( "Could not find validation entity, requeueing (package: {PackageId} {PackageVersion}, validationId: {ValidationId})", message.PackageId, message.PackageVersion, message.ValidationId); // Message may be retried. return(false); } else if (validation.State == ValidationStatus.NotStarted) { _logger.LogWarning( "Unexpected signature verification status '{ValidatorState}' when 'Incomplete' was expected, requeueing (package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", validation.State, message.PackageId, message.PackageVersion, message.ValidationId); // Message may be retried. return(false); } else if (validation.State != ValidationStatus.Incomplete) { _logger.LogWarning( "Terminal signature verification status '{ValidatorState}' when 'Incomplete' was expected, dropping message (package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", validation.State, message.PackageId, message.PackageVersion, message.ValidationId); // Consume the message. return(true); } // Validate package using (var packageStream = await _packageDownloader.DownloadAsync(message.NupkgUri, cancellationToken)) { var result = await _signatureValidator.ValidateAsync( validation.PackageKey, packageStream, message, cancellationToken); validation.State = result.State; // Save any issues if the resulting state is terminal. if (validation.State == ValidationStatus.Failed || validation.State == ValidationStatus.Succeeded) { validation.ValidatorIssues = validation.ValidatorIssues ?? new List <ValidatorIssue>(); foreach (var issue in result.Issues) { validation.ValidatorIssues.Add(new ValidatorIssue { IssueCode = issue.IssueCode, Data = issue.Serialize(), }); } } // Save the .nupkg URL if the resulting state is successful. if (validation.State == ValidationStatus.Succeeded && result.NupkgUri != null) { validation.NupkgUrl = result.NupkgUri.AbsoluteUri; } } // The signature validator should do all of the work to bring this validation to its completion. if (validation.State != ValidationStatus.Succeeded && validation.State != ValidationStatus.Failed) { _logger.LogError("The signature validator should have set the status 'Succeeded' or 'Failed', not " + "'{ValidatorState}' (package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", validation.State, message.PackageId, message.PackageVersion, message.ValidationId); return(false); } // Save the resulting validation status. var completed = await SaveStatusAsync(validation, message); if (completed && _featureFlagService.IsQueueBackEnabled()) { _logger.LogInformation("Sending queue-back message for validation {ValidationId}.", message.ValidationId); var messageData = PackageValidationMessageData.NewCheckValidator(message.ValidationId); await _validationEnqueuer.SendMessageAsync(messageData); } return(completed); } }
public async Task <bool> HandleAsync(SymbolsValidatorMessage message) { using (_logger.BeginScope("{ValidatorName}: Handling message for {PackageId} {PackageVersion} validation set {ValidationId}", ValidatorName.SymbolsValidator, message.PackageId, message.PackageNormalizedVersion, message.ValidationId)) { if (message == null) { throw new ArgumentNullException(nameof(message)); } var validation = await _validatorStateService.GetStatusAsync(message.ValidationId); // A validation should be queued with ValidatorState == Incomplete. if (validation == null) { _logger.LogInformation( "{ValidatorName} : Could not find validation entity, requeueing (package: {PackageId} {PackageVersion}, validationId: {ValidationId})", ValidatorName.SymbolsValidator, message.PackageId, message.PackageNormalizedVersion, message.ValidationId); // Message may be retried. return(false); } else if (validation.State == ValidationStatus.NotStarted) { _logger.LogWarning( "{ValidatorName}:Unexpected status '{ValidatorState}' when 'Incomplete' was expected, requeueing package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", ValidatorName.SymbolsValidator, validation.State, message.PackageId, message.PackageNormalizedVersion, message.ValidationId); // Message may be retried. return(false); } // Final states else if (validation.State == ValidationStatus.Failed || validation.State == ValidationStatus.Succeeded) { _logger.LogWarning( "{ValidatorName}:Terminal symbol verification status '{ValidatorState}' when 'Incomplete' was expected, dropping message (package id: {PackageId} package version: {PackageVersion} validation id: {ValidationId})", ValidatorName.SymbolsValidator, validation.State, message.PackageId, message.PackageNormalizedVersion, message.ValidationId); // Consume the message. return(true); } var validationResult = await _symbolValidatorService.ValidateSymbolsAsync(message, CancellationToken.None); if (validationResult.Status == ValidationStatus.Failed || validationResult.Status == ValidationStatus.Succeeded) { validation.State = validationResult.Status; validation.ValidatorIssues = validation.ValidatorIssues ?? new List <ValidatorIssue>(); foreach (var issue in validationResult.Issues) { validation.ValidatorIssues.Add(new ValidatorIssue { IssueCode = issue.IssueCode, Data = issue.Serialize(), }); } if (validationResult.NupkgUrl != null) { validation.NupkgUrl = validationResult.NupkgUrl; } var completed = await SaveStatusAsync(validation, message, MaxDBSaveRetry); if (completed && _featureFlagService.IsQueueBackEnabled()) { _logger.LogInformation("Sending queue-back message for validation {ValidationId}.", message.ValidationId); var messageData = PackageValidationMessageData.NewCheckValidator(message.ValidationId); await _validationEnqueuer.SendMessageAsync(messageData); } return(completed); } _logger.LogWarning( "{ValidatorName}:The validation did not return a complete status for package {PackageId} {PackageVersion} for validation id: {ValidationId} .", ValidatorName.SymbolsValidator, message.PackageId, message.PackageNormalizedVersion, message.ValidationId); return(false); } }