Skip to content
This repository was archived by the owner on Jul 30, 2024. It is now read-only.

Commit 182b655

Browse files
authored
[Revalidation] Add Package Revalidation State (#481)
This change adds the state used to track whether the job has been initialized or killswitched. The state is also used to track the desired event rate, which is used to speed up the job up over time. This change does not include health checks and will not slow down revalidations if the ingestion pipeline is unhealthy. This will be addressed in follow-up changes. Addresses https://github.com/NuGet/Engineering/issues/1440 Partially addresses https://github.com/nuget/engineering/issues/1441
1 parent 9061408 commit 182b655

31 files changed

Lines changed: 1018 additions & 154 deletions

src/NuGet.Jobs.Common/NuGet.Jobs.Common.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,13 @@
7474
<Version>1.50.2</Version>
7575
</PackageReference>
7676
<PackageReference Include="NuGet.Services.Configuration">
77-
<Version>2.25.0</Version>
77+
<Version>2.27.0</Version>
7878
</PackageReference>
7979
<PackageReference Include="NuGet.Services.KeyVault">
80-
<Version>2.26.0-master-33196</Version>
80+
<Version>2.27.0</Version>
8181
</PackageReference>
8282
<PackageReference Include="NuGet.Services.Logging">
83-
<Version>2.25.0</Version>
83+
<Version>2.27.0</Version>
8484
</PackageReference>
8585
<PackageReference Include="System.Net.Http">
8686
<Version>4.3.3</Version>

src/NuGet.Services.Revalidate/Configuration/RevalidationConfiguration.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ namespace NuGet.Services.Revalidate
77
{
88
public class RevalidationConfiguration
99
{
10+
/// <summary>
11+
/// The lower limit for the desired package event rate (includes package pushes, lists, unlists, and revalidations).
12+
/// If the ingestion pipeline remains healthy, the job will increase its rate over time. If the ingestion pipeline becomes
13+
/// unhealthy, the job will reset its rate to this value.
14+
/// </summary>
15+
public int MinPackageEventRate { get; set; }
16+
17+
/// <summary>
18+
/// The revalidation job will speed up over time. This is the upper limit for the desired package event
19+
/// rate (includes package pushes, lists, unlists, and revalidations).
20+
/// </summary>
21+
public int MaxPackageEventRate { get; set; }
22+
1023
/// <summary>
1124
/// The time before the revalidation job restarts itself.
1225
/// </summary>

src/NuGet.Services.Revalidate/Initialization/InitializationManager.cs

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,35 @@ public class InitializationManager
1515
{
1616
private static int BatchSize = 1000;
1717

18-
private readonly IRevalidationStateService _revalidationState;
18+
private readonly IRevalidationJobStateService _jobState;
19+
private readonly IPackageRevalidationStateService _packageState;
1920
private readonly IPackageFinder _packageFinder;
2021
private readonly InitializationConfiguration _config;
2122
private readonly ILogger<InitializationManager> _logger;
2223

2324
public InitializationManager(
24-
IRevalidationStateService revalidationState,
25+
IRevalidationJobStateService jobState,
26+
IPackageRevalidationStateService packageState,
2527
IPackageFinder packageFinder,
2628
InitializationConfiguration config,
2729
ILogger<InitializationManager> logger)
2830
{
29-
// TODO: Accept service for settings (IsInitialized, etc...)
30-
// See: https://github.com/NuGet/Engineering/issues/1440
31-
_revalidationState = revalidationState ?? throw new ArgumentNullException(nameof(revalidationState));
31+
_jobState = jobState ?? throw new ArgumentNullException(nameof(jobState));
32+
_packageState = packageState ?? throw new ArgumentNullException(nameof(packageState));
3233
_packageFinder = packageFinder ?? throw new ArgumentNullException(nameof(packageFinder));
3334
_config = config ?? throw new ArgumentNullException(nameof(config));
3435
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
3536
}
3637

3738
public async Task InitializeAsync()
3839
{
39-
// TODO: Check "IsInitialized" setting. If true, error!
40-
// See: https://github.com/NuGet/Engineering/issues/1440
40+
if (await _jobState.IsInitializedAsync())
41+
{
42+
_logger.LogError("Attempted to initialize the revalidation job when it is already initialized!");
43+
44+
throw new InvalidOperationException("Attempted to initialize the revalidation job when it is already initialized!");
45+
}
46+
4147
await ClearPackageRevalidationStateAsync();
4248

4349
// Find packages owned by Microsoft or preinstalled by Visual Studio.
@@ -66,16 +72,20 @@ public async Task InitializeAsync()
6672
await InitializePackageSetAsync(PackageFinder.DependencySetName, dependencyPackages);
6773
await InitializePackageSetAsync(PackageFinder.RemainingSetName, remainingPackages);
6874

69-
// TODO: Set "IsInitialized" setting to true
70-
// See: https://github.com/NuGet/Engineering/issues/1440
75+
await _jobState.MarkAsInitializedAsync();
7176
}
7277

7378
public async Task VerifyInitializationAsync()
7479
{
75-
// TODO: Check "IsInitialized" setting. If false, error!
76-
// See: https://github.com/NuGet/Engineering/issues/1440
80+
if (!await _jobState.IsInitializedAsync())
81+
{
82+
_logger.LogError("Expected revalidation state to be initialized");
83+
84+
throw new Exception("Expected revalidation state to be initialized");
85+
}
86+
7787
var expectedCount = _packageFinder.AppropriatePackageCount();
78-
var actualCount = await _revalidationState.PackageRevalidationCountAsync();
88+
var actualCount = await _packageState.PackageRevalidationCountAsync();
7989

8090
if (actualCount != expectedCount)
8191
{
@@ -93,7 +103,7 @@ private async Task ClearPackageRevalidationStateAsync()
93103

94104
do
95105
{
96-
removedRevalidations = await _revalidationState.RemoveRevalidationsAsync(BatchSize);
106+
removedRevalidations = await _packageState.RemovePackageRevalidationsAsync(BatchSize);
97107

98108
if (removedRevalidations > 0)
99109
{
@@ -120,9 +130,19 @@ private async Task InitializePackageSetAsync(string setName, HashSet<int> packag
120130

121131
for (var chunkIndex = 0; chunkIndex < chunks.Count; chunkIndex++)
122132
{
123-
// TODO: Check the kill switch
124-
// See https://github.com/NuGet/Engineering/issues/1440
125-
_logger.LogInformation("Initializing chunk {Chunk} of {Chunks} for package set {SetName}...",
133+
while (await _jobState.IsKillswitchActiveAsync())
134+
{
135+
_logger.LogInformation(
136+
"Delaying initialization of chunk {Chunk} of {Chunks} for package set {SetName} due to active killswitch",
137+
chunkIndex + 1,
138+
chunks.Count,
139+
setName);
140+
141+
await Task.Delay(_config.SleepDurationBetweenBatches);
142+
}
143+
144+
_logger.LogInformation(
145+
"Initializing chunk {Chunk} of {Chunks} for package set {SetName}...",
126146
chunkIndex + 1,
127147
chunks.Count,
128148
setName);
@@ -132,7 +152,8 @@ private async Task InitializePackageSetAsync(string setName, HashSet<int> packag
132152

133153
await InitializeRevalidationsAsync(chunk, versions);
134154

135-
_logger.LogInformation("Initialized chunk {Chunk} of {Chunks} for package set {SetName}",
155+
_logger.LogInformation(
156+
"Initialized chunk {Chunk} of {Chunks} for package set {SetName}",
136157
chunkIndex + 1,
137158
chunks.Count,
138159
setName);
@@ -184,7 +205,7 @@ private async Task InitializeRevalidationsAsync(
184205
}
185206
}
186207

187-
await _revalidationState.AddPackageRevalidationsAsync(revalidations);
208+
await _packageState.AddPackageRevalidationsAsync(revalidations);
188209
}
189210
}
190211
}

src/NuGet.Services.Revalidate/Job.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ protected override void ConfigureJobServices(IServiceCollection services, IConfi
109109
services.AddTransient<ITelemetryService, TelemetryService>();
110110
services.AddTransient<ITelemetryClient, TelemetryClientWrapper>();
111111

112-
services.AddTransient<IRevalidationStateService, RevalidationStateService>();
112+
services.AddTransient<IPackageRevalidationStateService, PackageRevalidationStateService>();
113+
services.AddTransient<IRevalidationJobStateService, RevalidationJobStateService>();
114+
services.AddTransient<NuGetGallery.IRevalidationStateService, NuGetGallery.RevalidationStateService>();
113115

114116
// Initialization
115117
services.AddTransient<IPackageFinder, PackageFinder>();

src/NuGet.Services.Revalidate/NuGet.Services.Revalidate.csproj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,17 @@
5454
<Compile Include="Services\HealthService.cs" />
5555
<Compile Include="Services\IHealthService.cs" />
5656
<Compile Include="Services\IRevalidationQueue.cs" />
57-
<Compile Include="Services\IRevalidationStateService.cs" />
57+
<Compile Include="Services\IRevalidationJobStateService.cs" />
58+
<Compile Include="Services\IPackageRevalidationStateService.cs" />
5859
<Compile Include="Services\IRevalidationService.cs" />
5960
<Compile Include="Services\IRevalidationThrottler.cs" />
6061
<Compile Include="Services\ISingletonService.cs" />
62+
<Compile Include="Services\RevalidationOperation.cs" />
6163
<Compile Include="Services\RevalidationQueue.cs" />
6264
<Compile Include="Services\RevalidationResult.cs" />
6365
<Compile Include="Services\RevalidationService.cs" />
64-
<Compile Include="Services\RevalidationStateService.cs" />
66+
<Compile Include="Services\RevalidationJobStateService.cs" />
67+
<Compile Include="Services\PackageRevalidationStateService.cs" />
6568
<Compile Include="Services\RevalidationThrottler.cs" />
6669
<Compile Include="Services\SingletonService.cs" />
6770
<Compile Include="Services\TelemetryService.cs" />
@@ -99,6 +102,11 @@
99102
<Name>Validation.PackageSigning.Core</Name>
100103
</ProjectReference>
101104
</ItemGroup>
105+
<ItemGroup>
106+
<PackageReference Include="NuGet.Services.Storage">
107+
<Version>2.27.0</Version>
108+
</PackageReference>
109+
</ItemGroup>
102110
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
103111
<PropertyGroup>
104112
<SignPath>..\..\build</SignPath>

src/NuGet.Services.Revalidate/Services/IRevalidationStateService.cs renamed to src/NuGet.Services.Revalidate/Services/IPackageRevalidationStateService.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,37 @@
77

88
namespace NuGet.Services.Revalidate
99
{
10-
public interface IRevalidationStateService
10+
public interface IPackageRevalidationStateService
1111
{
12-
/// <summary>
13-
/// Check whether the killswitch has been activated. If it has, all revalidation operations should be halted.
14-
/// </summary>
15-
/// <returns>Whether the killswitch has been activated.</returns>
16-
Task<bool> IsKillswitchActiveAsync();
17-
1812
/// <summary>
1913
/// Add the new revalidations to the database.
2014
/// </summary>
2115
/// <returns>A task that completes once the revalidations have been saved.</returns>
2216
Task AddPackageRevalidationsAsync(IReadOnlyList<PackageRevalidation> revalidations);
2317

2418
/// <summary>
25-
/// Remove revalidations from the database.
19+
/// Remove package revalidation entities from the database.
2620
/// </summary>
2721
/// <returns>A task that returns the number of revalidations that have been removed.</returns>
28-
Task<int> RemoveRevalidationsAsync(int max);
22+
Task<int> RemovePackageRevalidationsAsync(int max);
2923

3024
/// <summary>
3125
/// Count the number of package revalidations in the database.
3226
/// </summary>
3327
/// <returns>The count of package revalidations in the database.</returns>
3428
Task<int> PackageRevalidationCountAsync();
3529

30+
/// <summary>
31+
/// Count the number of package revalidations that were enqueued in the past hour.
32+
/// </summary>
33+
/// <returns>The number of enqueued revalidations.</returns>
34+
Task<int> CountRevalidationsEnqueuedInPastHourAsync();
35+
3636
/// <summary>
3737
/// Update the package revalidation and mark is as enqueued.
3838
/// </summary>
3939
/// <param name="revalidation">The revalidation to update.</param>
4040
/// <returns>A task that completes once the revalidation has been updated.</returns>
41-
Task MarkRevalidationAsEnqueuedAsync(PackageRevalidation revalidation);
41+
Task MarkPackageRevalidationAsEnqueuedAsync(PackageRevalidation revalidation);
4242
}
4343
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Threading.Tasks;
5+
6+
namespace NuGet.Services.Revalidate
7+
{
8+
/// <summary>
9+
/// The state shared between the Gallery and the revalidation job.
10+
/// </summary>
11+
public interface IRevalidationJobStateService
12+
{
13+
/// <summary>
14+
/// Check whether the revalidation state has been initialized.
15+
/// </summary>
16+
/// <returns>Whether the revalidation state has been initialized.</returns>
17+
Task<bool> IsInitializedAsync();
18+
19+
/// <summary>
20+
/// Update the settings to mark the revalidation job as initialized.
21+
/// </summary>
22+
/// <returns>A task that completes once the settings have been updated.</returns>
23+
Task MarkAsInitializedAsync();
24+
25+
/// <summary>
26+
/// Check whether the killswitch has been activated. If it has, all revalidation operations should be halted.
27+
/// </summary>
28+
/// <returns>Whether the killswitch has been activated.</returns>
29+
Task<bool> IsKillswitchActiveAsync();
30+
31+
/// <summary>
32+
/// Determine the desired package event rate per hour. Package events include package pushes,
33+
/// edits, and revalidations.
34+
/// </summary>
35+
/// <returns>The desired maximum number of package events per hour.</returns>
36+
Task<int> GetDesiredPackageEventRateAsync();
37+
38+
/// <summary>
39+
/// Reset the desired package event rate to the configured minimum.
40+
/// </summary>
41+
/// <returns>A task that completes once the rate has been reset.</returns>
42+
Task ResetDesiredPackageEventRateAsync();
43+
44+
/// <summary>
45+
/// Increment the desired package event rate per hour.
46+
/// </summary>
47+
/// <returns>A task that completes once the rate has been incremented.</returns>
48+
Task IncreaseDesiredPackageEventRateAsync();
49+
}
50+
}

src/NuGet.Services.Revalidate/Services/IRevalidationThrottler.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,6 @@ public interface IRevalidationThrottler
1313
/// <returns>If true, no more revalidations should be performed.</returns>
1414
Task<bool> IsThrottledAsync();
1515

16-
/// <summary>
17-
/// Reset the capacity to the configured minimum value. Call this when the service's status is degraded to
18-
/// throttle the revalidations.
19-
/// </summary>
20-
/// <returns>A task that completes once the capacity theshold has been reset.</returns>
21-
Task ResetCapacityAsync();
22-
23-
/// <summary>
24-
/// Increase the revalidation capacity by one revalidation per minute.
25-
/// </summary>
26-
/// <returns>A task taht completes once the capacity has been increased.</returns>
27-
Task IncreaseCapacityAsync();
28-
2916
/// <summary>
3017
/// Delay the current task to achieve the desired revalidation rate.
3118
/// </summary>

src/NuGet.Services.Revalidate/Services/ITelemetryService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4-
using System;
4+
using NuGet.Services.Logging;
55

66
namespace NuGet.Services.Revalidate
77
{
88
public interface ITelemetryService
99
{
10-
IDisposable TrackDurationToStartNextRevalidation();
10+
DurationMetric<StartNextRevalidationOperation> TrackStartNextRevalidationOperation();
1111

1212
void TrackPackageRevalidationMarkedAsCompleted(string packageId, string normalizedVersion);
1313

src/NuGet.Services.Revalidate/Services/RevalidationStateService.cs renamed to src/NuGet.Services.Revalidate/Services/PackageRevalidationStateService.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,17 @@
1212

1313
namespace NuGet.Services.Revalidate
1414
{
15-
public class RevalidationStateService : IRevalidationStateService
15+
public class PackageRevalidationStateService : IPackageRevalidationStateService
1616
{
1717
private readonly IValidationEntitiesContext _context;
18-
private readonly ILogger<RevalidationStateService> _logger;
18+
private readonly ILogger<PackageRevalidationStateService> _logger;
1919

20-
public RevalidationStateService(IValidationEntitiesContext context, ILogger<RevalidationStateService> logger)
20+
public PackageRevalidationStateService(IValidationEntitiesContext context, ILogger<PackageRevalidationStateService> logger)
2121
{
2222
_context = context ?? throw new ArgumentNullException(nameof(context));
2323
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
2424
}
2525

26-
public Task<bool> IsKillswitchActiveAsync()
27-
{
28-
// TODO
29-
return Task.FromResult(false);
30-
}
31-
3226
public async Task AddPackageRevalidationsAsync(IReadOnlyList<PackageRevalidation> revalidations)
3327
{
3428
var validationContext = _context as ValidationEntitiesContext;
@@ -53,7 +47,7 @@ public async Task AddPackageRevalidationsAsync(IReadOnlyList<PackageRevalidation
5347
}
5448
}
5549

56-
public async Task<int> RemoveRevalidationsAsync(int max)
50+
public async Task<int> RemovePackageRevalidationsAsync(int max)
5751
{
5852
var revalidations = await _context.PackageRevalidations
5953
.Take(max)
@@ -77,7 +71,16 @@ public async Task<int> PackageRevalidationCountAsync()
7771
return await _context.PackageRevalidations.CountAsync();
7872
}
7973

80-
public async Task MarkRevalidationAsEnqueuedAsync(PackageRevalidation revalidation)
74+
public async Task<int> CountRevalidationsEnqueuedInPastHourAsync()
75+
{
76+
var lowerBound = DateTime.UtcNow.Subtract(TimeSpan.FromHours(1));
77+
78+
return await _context.PackageRevalidations
79+
.Where(r => r.Enqueued >= lowerBound)
80+
.CountAsync();
81+
}
82+
83+
public async Task MarkPackageRevalidationAsEnqueuedAsync(PackageRevalidation revalidation)
8184
{
8285
try
8386
{

0 commit comments

Comments
 (0)