Skip to main content

NuGet.Services.Validation.Orchestrator

Overview

The Validation Orchestrator is a .NET Framework 4.7.2 console executable that manages (“orchestrates”) the end-to-end validation pipeline for packages submitted to nuget.org. It does not perform validation work itself — instead it acts as a state machine and dispatcher, coordinating a configurable graph of downstream validator jobs. When a package or symbol package is first published (or manually revalidated), its PackageStatusKey is set to Validating. The orchestrator’s job is to ensure that status eventually transitions to either Available or FailedValidation by driving all configured validators to completion.
The orchestrator runs as two separate deployment instances that share most of their code but have distinct Service Bus topics, validator sets, and configuration: one for .nupkg packages and one for .snupkg symbol packages.

Role in the NuGetGallery Ecosystem

Upstream: NuGetGallery

NuGetGallery enqueues a ProcessValidationSet Service Bus message when a package is published or an admin requests revalidation. It also creates the initial validation set record in the Validation DB.

Downstream: Validators

Each validator is a separate job (e.g., ProcessSignature, ValidateCertificate, ScanAndSign, SymbolsValidator) that the orchestrator starts and polls via its own Service Bus topic.

Downstream: Db2Catalog

When a package is marked Available, its LastEdited timestamp is updated, which triggers the Db2Catalog job to pick up the package and publish it into the V3 NuGet protocol feed.

Downstream: Email Job

On terminal outcomes (success or failure), the orchestrator enqueues email notifications to package owners via a dedicated email Service Bus topic.

Orchestration Algorithm

The core loop executed for each incoming Service Bus message:
  1. Look up (or create) a PackageValidationSet for the given tracking ID.
  2. For each in-progress (Incomplete) validation, call GetResponseAsync on its validator.
    • If succeeded or failed, persist the new status and call CleanUpAsync.
  3. For each not-started validation whose prerequisites are met, call StartAsync.
    • Repeat this loop if any start attempt returns Succeeded immediately (handles synchronous validators; capped at 20 iterations).
  4. Evaluate the outcome:
    • Any required validation failed — mark package FailedValidation, send failure email.
    • All required validations succeeded — mark package Available, send publish email.
    • Still in progress — re-enqueue a ProcessValidationSet message with a delay (ValidationMessageRecheckPeriod).
  5. Validators can also send a CheckValidator “queue-back” message when they finish, so the orchestrator reacts immediately rather than waiting for the scheduled recheck.
Because the orchestrator is a Service Bus subscription listener with no singleton requirement, multiple instances can run in parallel safely. Optimistic concurrency on PackageValidationSet prevents double-processing terminal state changes.

Service Bus Message Shapes

Key Files and Classes

Dependencies

Internal Project References

Key NuGet / Framework Dependencies

Notable Patterns and Implementation Details

Dual-mode deployment. A single compiled binary serves as both the Package Orchestrator and the Symbols Orchestrator. The OrchestrationRunnerConfiguration.ValidatingType config value (Package or SymbolPackage) switches which message handler, validators, file metadata service, and status processor are registered — resolved entirely at DI composition time in Job.ConfigureAutofacServices and Job.ConfigureJobServices.
Validator dependency graph. Each ValidationConfigurationItem carries a RequiredValidations list (validator names that must reach Succeeded before this validator starts). ValidationSetProcessor.ArePrerequisitesMet checks that all named prerequisites are satisfied. TopologicalSort verifies there are no cycles at startup via ConfigurationValidator.Validate().
Processors cannot run in parallel. Validators that implement INuGetProcessor (e.g., ScanAndSignProcessor, PackageSignatureProcessor) modify the package blob. Running two processors concurrently could result in operating on divergent blob versions. The RequiredValidations dependency graph must be configured to enforce strictly sequential execution of all processors.
Several validators have closed-source backing jobs. ScanAndSignProcessor (malware scanning + repository signing), SymbolScanValidator (symbol malware scan), and SymbolsIngester (Microsoft symbol server) integrate with internal Microsoft services not present in this repository. Only the orchestrator-side enqueuer stubs and state-tracking code are here.
AllowedToFail validators. A validator with FailureBehavior = AllowedToFail is optional — its failure does not block the package from becoming Available. However, if such a validator is still Incomplete when all required validators succeed, the orchestrator marks the package Available immediately and continues scheduling rechecks until the optional validator reaches a terminal state, then deletes the validation-storage blob.
Process recycling pattern. OrchestrationRunner starts the subscription processor, sleeps for ProcessRecycleInterval (typically ~24 hours), then initiates a graceful shutdown and the executable exits. The host restarts it (managed by NSSM, per Scripts/nssm.exe). This bounds memory growth and ensures periodic config and certificate refresh without requiring a true long-running daemon.
CheckValidator queue-back optimization. Downstream validators enqueue a lightweight CheckValidator message (SchemaName: PackageValidationCheckValidatorMessageData) directly back to the orchestrator’s own Service Bus topic when they complete. This lets the orchestrator react within seconds rather than waiting for the next scheduled ProcessValidationSet recheck cycle, which is controlled by ValidationMessageRecheckPeriod.