Skip to content
This repository has been archived by the owner on Jul 30, 2024. It is now read-only.
/ NuGet.Jobs Public archive

Commit

Permalink
Refactor Auxiliary2AzureSearch to split steps into classes (#747)
Browse files Browse the repository at this point in the history
  • Loading branch information
joelverhagen committed Feb 20, 2020
1 parent 8499c55 commit 4b78882
Show file tree
Hide file tree
Showing 10 changed files with 580 additions and 400 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NuGet.Services.AzureSearch.AuxiliaryFiles;
using NuGetGallery;

namespace NuGet.Services.AzureSearch.Auxiliary2AzureSearch
{
public class UpdateVerifiedPackagesCommand : IAzureSearchCommand
{
private readonly IDatabaseAuxiliaryDataFetcher _databaseFetcher;
private readonly IVerifiedPackagesDataClient _verifiedPackagesDataClient;
private readonly IAzureSearchTelemetryService _telemetryService;
private readonly ILogger<Auxiliary2AzureSearchCommand> _logger;
private readonly StringCache _stringCache;

public UpdateVerifiedPackagesCommand(
IDatabaseAuxiliaryDataFetcher databaseFetcher,
IVerifiedPackagesDataClient verifiedPackagesDataClient,
IAzureSearchTelemetryService telemetryService,
ILogger<Auxiliary2AzureSearchCommand> logger)
{
_databaseFetcher = databaseFetcher ?? throw new ArgumentNullException(nameof(databaseFetcher));
_verifiedPackagesDataClient = verifiedPackagesDataClient ?? throw new ArgumentNullException(nameof(verifiedPackagesDataClient));
_telemetryService = telemetryService ?? throw new ArgumentNullException(nameof(telemetryService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_stringCache = new StringCache();
}

public async Task ExecuteAsync()
{
var stopwatch = Stopwatch.StartNew();
var outcome = JobOutcome.Failure;
try
{
outcome = await UpdateVerifiedPackagesAsync() ? JobOutcome.Success : JobOutcome.NoOp;
}
finally
{
stopwatch.Stop();
_telemetryService.TrackUpdateVerifiedPackagesCompleted(outcome, stopwatch.Elapsed);
}
}

private async Task<bool> UpdateVerifiedPackagesAsync()
{
// The "old" data in this case is the latest file that was copied to the region's storage container by this
// job (or initialized by Db2AzureSearch).
var oldResult = await _verifiedPackagesDataClient.ReadLatestAsync(
AccessConditionWrapper.GenerateEmptyCondition(),
_stringCache);

// The "new" data in this case is from the database.
var newData = await _databaseFetcher.GetVerifiedPackagesAsync();

var changes = new HashSet<string>(oldResult.Data, oldResult.Data.Comparer);
changes.SymmetricExceptWith(newData);
_logger.LogInformation("{Count} package IDs have verified status changes.", changes.Count);

if (changes.Count == 0)
{
return false;
}
else
{
await _verifiedPackagesDataClient.ReplaceLatestAsync(newData, oldResult.Metadata.GetIfMatchCondition());
return true;
}
}
}
}
22 changes: 22 additions & 0 deletions src/NuGet.Services.AzureSearch/AzureSearchTelemetryService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -404,5 +404,27 @@ public void TrackReadLatestVerifiedPackagesFromDatabase(int packageIdCount, Time
{ "PackageIdCount", packageIdCount.ToString() },
});
}

public void TrackUpdateVerifiedPackagesCompleted(JobOutcome outcome, TimeSpan elapsed)
{
_telemetryClient.TrackMetric(
Prefix + "UpdateVerifiedPackagesCompletedSeconds",
elapsed.TotalSeconds,
new Dictionary<string, string>
{
{ "Outcome", outcome.ToString() },
});
}

public void TrackUpdateDownloadsCompleted(JobOutcome outcome, TimeSpan elapsed)
{
_telemetryClient.TrackMetric(
Prefix + "UpdateDownloadsCompletedSeconds",
elapsed.TotalSeconds,
new Dictionary<string, string>
{
{ "Outcome", outcome.ToString() },
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,13 @@ public static IServiceCollection AddAzureSearch(

services.AddSingleton<ISecretRefresher, SecretRefresher>();

services.AddTransient<Auxiliary2AzureSearchCommand>();
services.AddTransient<UpdateVerifiedPackagesCommand>();
services.AddTransient<UpdateDownloadsCommand>();
services.AddTransient(p => new Auxiliary2AzureSearchCommand(
p.GetRequiredService<UpdateVerifiedPackagesCommand>(),
p.GetRequiredService<UpdateDownloadsCommand>(),
p.GetRequiredService<IAzureSearchTelemetryService>(),
p.GetRequiredService<ILogger<Auxiliary2AzureSearchCommand>>()));
services.AddTransient<Owners2AzureSearchCommand>();

services.AddTransient<IAzureSearchTelemetryService, AzureSearchTelemetryService>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ void TrackDownloadCountDecrease(
void TrackV3GetDocument(TimeSpan elapsed);
void TrackV2GetDocumentWithSearchIndex(TimeSpan elapsed);
void TrackV2GetDocumentWithHijackIndex(TimeSpan elapsed);
void TrackUpdateVerifiedPackagesCompleted(JobOutcome outcome, TimeSpan elapsed);
void TrackReadLatestVerifiedPackages(int? packageIdCount, bool notModified, TimeSpan elapsed);
IDisposable TrackReplaceLatestVerifiedPackages(int packageIdCount);
void TrackAuxiliaryFilesStringCache(int stringCount, long charCount, int requestCount, int hitCount);
void TrackUpdateDownloadsCompleted(JobOutcome outcome, TimeSpan elapsed);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
<Compile Include="Analysis\PackageIdCustomAnalyzer.cs" />
<Compile Include="Analysis\PackageIdCustomTokenizer.cs" />
<Compile Include="Analysis\TruncateCustomTokenFilter.cs" />
<Compile Include="Auxiliary2AzureSearch\UpdateDownloadsCommand.cs" />
<Compile Include="Auxiliary2AzureSearch\UpdateVerifiedPackagesCommand.cs" />
<Compile Include="Auxiliary2AzureSearch\Auxiliary2AzureSearchCommand.cs" />
<Compile Include="Auxiliary2AzureSearch\Auxiliary2AzureSearchConfiguration.cs" />
<Compile Include="Auxiliary2AzureSearch\DownloadSetComparer.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using Castle.Core.Logging;
using Microsoft.Azure.Search.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -21,55 +19,14 @@

namespace NuGet.Services.AzureSearch.Auxiliary2AzureSearch
{
public class Auxiliary2AzureSearchCommandFacts
public class UpdateDownloadsCommandFacts
{
public class ExecuteAsync : Facts
{
public ExecuteAsync(ITestOutputHelper output) : base(output)
{
}

[Fact]
public async Task PushesAddedVerifiedPackage()
{
NewVerifiedPackagesData.Add("NuGet.Versioning");

await Target.ExecuteAsync();

VerifyCompletedTelemetry(JobOutcome.Success);
VerifiedPackagesDataClient.Verify(
x => x.ReplaceLatestAsync(
NewVerifiedPackagesData,
It.Is<IAccessCondition>(a => a.IfMatchETag == OldVerifiedPackagesResult.Metadata.ETag)),
Times.Once);
}

[Fact]
public async Task PushesRemovedVerifiedPackage()
{
OldVerifiedPackagesData.Add("NuGet.Versioning");

await Target.ExecuteAsync();

VerifyCompletedTelemetry(JobOutcome.Success);
VerifiedPackagesDataClient.Verify(
x => x.ReplaceLatestAsync(
NewVerifiedPackagesData,
It.Is<IAccessCondition>(a => a.IfMatchETag == OldVerifiedPackagesResult.Metadata.ETag)),
Times.Once);
}

[Fact]
public async Task DoesNotPushUnchangedVerifiedPackages()
{
await Target.ExecuteAsync();

VerifyCompletedTelemetry(JobOutcome.NoOp);
VerifiedPackagesDataClient.Verify(
x => x.ReplaceLatestAsync(It.IsAny<HashSet<string>>(), It.IsAny<IAccessCondition>()),
Times.Never);
}

[Fact]
public async Task PushesNothingWhenThereAreNoChanges()
{
Expand Down Expand Up @@ -372,9 +329,7 @@ public abstract class Facts
public Facts(ITestOutputHelper output)
{
AuxiliaryFileClient = new Mock<IAuxiliaryFileClient>();
DatabaseAuxiliaryDataFetcher = new Mock<IDatabaseAuxiliaryDataFetcher>();
DownloadDataClient = new Mock<IDownloadDataClient>();
VerifiedPackagesDataClient = new Mock<IVerifiedPackagesDataClient>();
DownloadSetComparer = new Mock<IDownloadSetComparer>();
SearchDocumentBuilder = new Mock<ISearchDocumentBuilder>();
IndexActionBuilder = new Mock<ISearchIndexActionBuilder>();
Expand Down Expand Up @@ -405,14 +360,6 @@ public Facts(ITestOutputHelper output)
.Setup(x => x.LoadDownloadOverridesAsync())
.ReturnsAsync(() => DownloadOverrides);

OldVerifiedPackagesData = new HashSet<string>();
OldVerifiedPackagesResult = Data.GetAuxiliaryFileResult(OldVerifiedPackagesData, "verified-packages-etag");
VerifiedPackagesDataClient
.Setup(x => x.ReadLatestAsync(It.IsAny<IAccessCondition>(), It.IsAny<StringCache>()))
.ReturnsAsync(() => OldVerifiedPackagesResult);
NewVerifiedPackagesData = new HashSet<string>();
DatabaseAuxiliaryDataFetcher.Setup(x => x.GetVerifiedPackagesAsync()).ReturnsAsync(() => NewVerifiedPackagesData);

Changes = new SortedDictionary<string, long>();
DownloadSetComparer
.Setup(x => x.Compare(It.IsAny<DownloadData>(), It.IsAny<DownloadData>()))
Expand Down Expand Up @@ -454,11 +401,9 @@ public Facts(ITestOutputHelper output)
CurrentBatch = new ConcurrentBag<IndexActions>();
});

Target = new Auxiliary2AzureSearchCommand(
Target = new UpdateDownloadsCommand(
AuxiliaryFileClient.Object,
DatabaseAuxiliaryDataFetcher.Object,
DownloadDataClient.Object,
VerifiedPackagesDataClient.Object,
DownloadSetComparer.Object,
SearchDocumentBuilder.Object,
IndexActionBuilder.Object,
Expand All @@ -470,9 +415,7 @@ public Facts(ITestOutputHelper output)
}

public Mock<IAuxiliaryFileClient> AuxiliaryFileClient { get; }
public Mock<IDatabaseAuxiliaryDataFetcher> DatabaseAuxiliaryDataFetcher { get; }
public Mock<IDownloadDataClient> DownloadDataClient { get; }
public Mock<IVerifiedPackagesDataClient> VerifiedPackagesDataClient { get; }
public Mock<IDownloadSetComparer> DownloadSetComparer { get; }
public Mock<ISearchDocumentBuilder> SearchDocumentBuilder { get; }
public Mock<ISearchIndexActionBuilder> IndexActionBuilder { get; }
Expand All @@ -487,23 +430,20 @@ public Facts(ITestOutputHelper output)
public DownloadData NewDownloadData { get; }
public Dictionary<string, long> DownloadOverrides { get; }
public SortedDictionary<string, long> Changes { get; }
public Auxiliary2AzureSearchCommand Target { get; }
public UpdateDownloadsCommand Target { get; }
public IndexActions IndexActions { get; set; }
public ConcurrentBag<string> ProcessedIds { get; }
public ConcurrentBag<string> PushedIds { get; }
public ConcurrentBag<IndexActions> CurrentBatch { get; set; }
public ConcurrentBag<List<IndexActions>> FinishedBatches { get; }
public HashSet<string> OldVerifiedPackagesData { get; }
public AuxiliaryFileResult<HashSet<string>> OldVerifiedPackagesResult { get; }
public HashSet<string> NewVerifiedPackagesData { get; }

public void VerifyCompletedTelemetry(JobOutcome outcome)
{
TelemetryService.Verify(
x => x.TrackAuxiliary2AzureSearchCompleted(It.IsAny<JobOutcome>(), It.IsAny<TimeSpan>()),
x => x.TrackUpdateDownloadsCompleted(It.IsAny<JobOutcome>(), It.IsAny<TimeSpan>()),
Times.Once);
TelemetryService.Verify(
x => x.TrackAuxiliary2AzureSearchCompleted(outcome, It.IsAny<TimeSpan>()),
x => x.TrackUpdateDownloadsCompleted(outcome, It.IsAny<TimeSpan>()),
Times.Once);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Moq;
using NuGet.Services.AzureSearch.AuxiliaryFiles;
using NuGet.Services.AzureSearch.Support;
using NuGetGallery;
using Xunit;
using Xunit.Abstractions;

namespace NuGet.Services.AzureSearch.Auxiliary2AzureSearch
{
public class UpdateVerifiedPackagesCommandFacts
{
public class ExecuteAsync : Facts
{
public ExecuteAsync(ITestOutputHelper output) : base(output)
{
}

[Fact]
public async Task PushesAddedVerifiedPackage()
{
NewVerifiedPackagesData.Add("NuGet.Versioning");

await Target.ExecuteAsync();

VerifyCompletedTelemetry(JobOutcome.Success);
VerifiedPackagesDataClient.Verify(
x => x.ReplaceLatestAsync(
NewVerifiedPackagesData,
It.Is<IAccessCondition>(a => a.IfMatchETag == OldVerifiedPackagesResult.Metadata.ETag)),
Times.Once);
}

[Fact]
public async Task PushesRemovedVerifiedPackage()
{
OldVerifiedPackagesData.Add("NuGet.Versioning");

await Target.ExecuteAsync();

VerifyCompletedTelemetry(JobOutcome.Success);
VerifiedPackagesDataClient.Verify(
x => x.ReplaceLatestAsync(
NewVerifiedPackagesData,
It.Is<IAccessCondition>(a => a.IfMatchETag == OldVerifiedPackagesResult.Metadata.ETag)),
Times.Once);
}

[Fact]
public async Task DoesNotPushUnchangedVerifiedPackages()
{
await Target.ExecuteAsync();

VerifyCompletedTelemetry(JobOutcome.NoOp);
VerifiedPackagesDataClient.Verify(
x => x.ReplaceLatestAsync(It.IsAny<HashSet<string>>(), It.IsAny<IAccessCondition>()),
Times.Never);
}
}

public abstract class Facts
{
public Facts(ITestOutputHelper output)
{
DatabaseAuxiliaryDataFetcher = new Mock<IDatabaseAuxiliaryDataFetcher>();
VerifiedPackagesDataClient = new Mock<IVerifiedPackagesDataClient>();
TelemetryService = new Mock<IAzureSearchTelemetryService>();
Logger = output.GetLogger<Auxiliary2AzureSearchCommand>();

OldVerifiedPackagesData = new HashSet<string>();
OldVerifiedPackagesResult = Data.GetAuxiliaryFileResult(OldVerifiedPackagesData, "verified-packages-etag");
VerifiedPackagesDataClient
.Setup(x => x.ReadLatestAsync(It.IsAny<IAccessCondition>(), It.IsAny<StringCache>()))
.ReturnsAsync(() => OldVerifiedPackagesResult);
NewVerifiedPackagesData = new HashSet<string>();
DatabaseAuxiliaryDataFetcher.Setup(x => x.GetVerifiedPackagesAsync()).ReturnsAsync(() => NewVerifiedPackagesData);

Target = new UpdateVerifiedPackagesCommand(
DatabaseAuxiliaryDataFetcher.Object,
VerifiedPackagesDataClient.Object,
TelemetryService.Object,
Logger);
}

public Mock<IDatabaseAuxiliaryDataFetcher> DatabaseAuxiliaryDataFetcher { get; }
public Mock<IVerifiedPackagesDataClient> VerifiedPackagesDataClient { get; }
public Mock<IAzureSearchTelemetryService> TelemetryService { get; }
public RecordingLogger<Auxiliary2AzureSearchCommand> Logger { get; }
public UpdateVerifiedPackagesCommand Target { get; }
public HashSet<string> OldVerifiedPackagesData { get; }
public AuxiliaryFileResult<HashSet<string>> OldVerifiedPackagesResult { get; }
public HashSet<string> NewVerifiedPackagesData { get; }

public void VerifyCompletedTelemetry(JobOutcome outcome)
{
TelemetryService.Verify(
x => x.TrackUpdateVerifiedPackagesCompleted(It.IsAny<JobOutcome>(), It.IsAny<TimeSpan>()),
Times.Once);
TelemetryService.Verify(
x => x.TrackUpdateVerifiedPackagesCompleted(outcome, It.IsAny<TimeSpan>()),
Times.Once);
}
}
}
}
Loading

0 comments on commit 4b78882

Please sign in to comment.