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
Merge branch 'dev' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
joelverhagen committed Jul 24, 2018
2 parents 77f16e1 + 3ded005 commit 06270fc
Show file tree
Hide file tree
Showing 82 changed files with 2,571 additions and 137 deletions.
21 changes: 21 additions & 0 deletions NuGet.Jobs.sln
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.Revalidate",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.Revalidate.Tests", "tests\NuGet.Services.Revalidate.Tests\NuGet.Services.Revalidate.Tests.csproj", "{19780DCB-B307-4254-B10C-4335FC784DEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Validation.Symbols.Core", "src\Validation.Symbols.Core\Validation.Symbols.Core.csproj", "{17510A22-176F-4E96-A867-E79F1B54F54F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Monitoring.RebootSearchInstance", "src\Monitoring.RebootSearchInstance\Monitoring.RebootSearchInstance.csproj", "{ECD8DFCE-8E3C-4510-AFE3-D7EC168E8D66}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Monitoring.RebootSearchInstance.Tests", "tests\Monitoring.RebootSearchInstance.Tests\Monitoring.RebootSearchInstance.Tests.csproj", "{21C0A0EE-8696-4013-950F-D6495D0C6E40}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -351,6 +357,18 @@ Global
{19780DCB-B307-4254-B10C-4335FC784DEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19780DCB-B307-4254-B10C-4335FC784DEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19780DCB-B307-4254-B10C-4335FC784DEA}.Release|Any CPU.Build.0 = Release|Any CPU
{17510A22-176F-4E96-A867-E79F1B54F54F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17510A22-176F-4E96-A867-E79F1B54F54F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17510A22-176F-4E96-A867-E79F1B54F54F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17510A22-176F-4E96-A867-E79F1B54F54F}.Release|Any CPU.Build.0 = Release|Any CPU
{ECD8DFCE-8E3C-4510-AFE3-D7EC168E8D66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ECD8DFCE-8E3C-4510-AFE3-D7EC168E8D66}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ECD8DFCE-8E3C-4510-AFE3-D7EC168E8D66}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ECD8DFCE-8E3C-4510-AFE3-D7EC168E8D66}.Release|Any CPU.Build.0 = Release|Any CPU
{21C0A0EE-8696-4013-950F-D6495D0C6E40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21C0A0EE-8696-4013-950F-D6495D0C6E40}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21C0A0EE-8696-4013-950F-D6495D0C6E40}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21C0A0EE-8696-4013-950F-D6495D0C6E40}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -408,6 +426,9 @@ Global
{60152AB1-2EB4-4D44-B6D6-EEE24209A1F7} = {6A776396-02B1-475D-A104-26940ADB04AB}
{1963909D-8BE3-4CB8-B57E-AB6A8CB22FED} = {678D7B14-F8BC-4193-99AF-2EE8AA390A02}
{19780DCB-B307-4254-B10C-4335FC784DEA} = {6A776396-02B1-475D-A104-26940ADB04AB}
{17510A22-176F-4E96-A867-E79F1B54F54F} = {678D7B14-F8BC-4193-99AF-2EE8AA390A02}
{ECD8DFCE-8E3C-4510-AFE3-D7EC168E8D66} = {814F9B31-4AF3-46CC-AD61-CEB40F47083A}
{21C0A0EE-8696-4013-950F-D6495D0C6E40} = {6A776396-02B1-475D-A104-26940ADB04AB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {284A7AC3-FB43-4F1F-9C9C-2AF0E1F46C2B}
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ NuGet.Jobs
7. Also, add settings.job file to mark the job as singleton, if the job will be run as a webjob, and it be a continuously running singleton
## Specific instructions
This repository has a lot of jobs used for completely different purposes. For this reason, each should should have its
own documentation. This specific documentation is far from complete... but you have to start somewhere!
- [Monitoring.RebootSearchInstance](src/Monitoring.RebootSearchInstance/README.md) - check each region for stuck search instances and restart them
Open Source Code of Conduct
===================
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
8 changes: 6 additions & 2 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ Invoke-BuildStep 'Set version metadata in AssemblyInfo.cs' { `
"$PSScriptRoot\src\NuGet.Jobs.Common\Properties\AssemblyInfo.g.cs",
"$PSScriptRoot\src\Validation.Common.Job\Properties\AssemblyInfo.g.cs",
"$PSScriptRoot\src\Validation.ScanAndSign.Core\Properties\AssemblyInfo.g.cs",
"$PSScriptRoot\src\PackageLagMonitor\Properties\AssemblyInfo.g.cs"
"$PSScriptRoot\src\PackageLagMonitor\Properties\AssemblyInfo.g.cs",
"$PSScriptRoot\src\Validation.Symbols.Core\Properties\AssemblyInfo.g.cs",
"$PSScriptRoot\src\Monitoring.RebootSearchInstance\Properties\AssemblyInfo.g.cs"

$versionMetadata | ForEach-Object {
Set-VersionInfo -Path $_ -Version $SimpleVersion -Branch $Branch -Commit $CommitSHA
Expand Down Expand Up @@ -173,7 +175,9 @@ Invoke-BuildStep 'Creating artifacts' {
"src/Validation.PackageSigning.ProcessSignature/Validation.PackageSigning.ProcessSignature.csproj", `
"src/Validation.PackageSigning.ValidateCertificate/Validation.PackageSigning.ValidateCertificate.csproj", `
"src/Validation.PackageSigning.RevalidateCertificate/Validation.PackageSigning.RevalidateCertificate.csproj", `
"src/PackageLagMonitor/Monitoring.PackageLag.csproj" `
"src/PackageLagMonitor/Monitoring.PackageLag.csproj", `
"src/Validation.Symbols.Core/Validation.Symbols.Core.csproj", `
"src/Monitoring.RebootSearchInstance/Monitoring.RebootSearchInstance.csproj" `
+ $ProjectsWithSymbols

Foreach ($Project in $Projects) {
Expand Down
6 changes: 6 additions & 0 deletions src/Monitoring.RebootSearchInstance/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
</configuration>
73 changes: 73 additions & 0 deletions src/Monitoring.RebootSearchInstance/FeedClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// 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.Globalization;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml.Linq;
using Autofac;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace NuGet.Monitoring.RebootSearchInstance
{
public class FeedClient : IFeedClient
{
private const string FeedRelativeUrl =
"api/v2/Packages?" +
"$filter={0}%20ne%20null&" +
"$top=1&" +
"$orderby={0}%20desc&" +
"$select={0}";

private static readonly IEnumerable<string> TimeStampProperties = new string[]
{
"Created",
"LastEdited",
};

private readonly HttpClient _httpClient;
private readonly IOptionsSnapshot<MonitorConfiguration> _configuration;
private readonly ILogger<FeedClient> _logger;

public FeedClient(HttpClient httpClient, IOptionsSnapshot<MonitorConfiguration> configuration, ILogger<FeedClient> logger)
{
_httpClient = httpClient;
_configuration = configuration;
_logger = logger;
}

public async Task<DateTimeOffset> GetLatestFeedTimeStampAsync()
{
var tasks = TimeStampProperties
.Select(GetLatestFeedTimeStampAsync)
.ToList();

await Task.WhenAll(tasks);

return tasks.Max(t => t.Result);
}

private async Task<DateTimeOffset> GetLatestFeedTimeStampAsync(string propertyName)
{
var galleryBaseUrl = _configuration.Value.FeedUrl;
var feedUrl = new Uri(galleryBaseUrl).GetLeftPart(UriPartial.Authority);
var url = $"{feedUrl}/{string.Format(FeedRelativeUrl, propertyName)}";
using (var stream = await _httpClient.GetStreamAsync(url))
{
var packagesResultObject = XDocument.Load(stream);
var propertyValue = DateTimeOffset.Parse(
packagesResultObject.Descendants()
.Where(a => a.Name.LocalName == propertyName)
.FirstOrDefault().Value,
formatProvider: null,
styles: DateTimeStyles.AssumeUniversal);
_logger.LogInformation("Feed at {GalleryBaseUrl} has {TimeStampPropertyName} cursor at {TimeStampPropertyValue}", galleryBaseUrl, propertyName, propertyValue);
return propertyValue;
}
}
}
}
13 changes: 13 additions & 0 deletions src/Monitoring.RebootSearchInstance/IFeedClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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.Threading.Tasks;

namespace NuGet.Monitoring.RebootSearchInstance
{
public interface IFeedClient
{
Task<DateTimeOffset> GetLatestFeedTimeStampAsync();
}
}
13 changes: 13 additions & 0 deletions src/Monitoring.RebootSearchInstance/ISearchInstanceRebooter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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.Threading;
using System.Threading.Tasks;

namespace NuGet.Monitoring.RebootSearchInstance
{
public interface ISearchInstanceRebooter
{
Task RunAsync(CancellationToken token);
}
}
17 changes: 17 additions & 0 deletions src/Monitoring.RebootSearchInstance/ITelemetryService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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;

namespace NuGet.Monitoring.RebootSearchInstance
{
public interface ITelemetryService
{
void TrackHealthyInstanceCount(string region, int count);
void TrackInstanceCount(string region, int count);
void TrackInstanceReboot(string region, int index);
void TrackInstanceRebootDuration(string region, int index, TimeSpan duration, InstanceHealth health);
void TrackUnhealthyInstanceCount(string region, int count);
void TrackUnknownInstanceCount(string region, int count);
}
}
12 changes: 12 additions & 0 deletions src/Monitoring.RebootSearchInstance/InstanceHealth.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 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.

namespace NuGet.Monitoring.RebootSearchInstance
{
public enum InstanceHealth
{
Healthy,
Unhealthy,
Unknown,
}
}
80 changes: 80 additions & 0 deletions src/Monitoring.RebootSearchInstance/Job.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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.Net;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NuGet.Jobs.Montoring.PackageLag;
using NuGet.Jobs.Validation;
using NuGet.Services.AzureManagement;

namespace NuGet.Monitoring.RebootSearchInstance
{
public class Job : JsonConfigurationJob
{
private const string AzureManagementSectionName = "AzureManagement";
private const string MonitorConfigurationSectionName = "MonitorConfiguration";

public override async Task Run()
{
using (var scope = _serviceProvider.CreateScope())
{
var rebooter = scope.ServiceProvider.GetRequiredService<ISearchInstanceRebooter>();
await rebooter.RunAsync(CancellationToken.None);
}
}

protected override void ConfigureJobServices(IServiceCollection services, IConfigurationRoot configurationRoot)
{
services.Configure<MonitorConfiguration>(configurationRoot.GetSection(MonitorConfigurationSectionName));
services.Configure<SearchServiceConfiguration>(configurationRoot.GetSection(MonitorConfigurationSectionName));
services.Configure<AzureManagementAPIWrapperConfiguration>(configurationRoot.GetSection(AzureManagementSectionName));

services.AddTransient<ITelemetryService, TelemetryService>();
services.AddTransient<ISearchInstanceRebooter, SearchInstanceRebooter>();
services.AddTransient<IFeedClient, FeedClient>();
services.AddTransient<ISearchServiceClient, SearchServiceClient>();
services.AddSingleton<IAzureManagementAPIWrapper, AzureManagementAPIWrapper>();
services.AddTransient<IAzureManagementAPIWrapperConfiguration>(p => p.GetService<IOptionsSnapshot<AzureManagementAPIWrapperConfiguration>>().Value);

services.AddSingleton(p =>
{
var assembly = Assembly.GetEntryAssembly();
var assemblyName = assembly.GetName().Name;
var assemblyVersion = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "0.0.0";

var client = new HttpClient(new WebRequestHandler
{
AllowPipelining = true,
AutomaticDecompression = (DecompressionMethods.GZip | DecompressionMethods.Deflate),
ServerCertificateCustomValidationCallback =
(httpRequestMessage, cert, cetChain, policyErrors) =>
{
if (policyErrors == System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch || policyErrors == System.Net.Security.SslPolicyErrors.None)
{
return true;
}

return false;
},
});

client.DefaultRequestHeaders.Add("User-Agent", $"{assemblyName}/{assemblyVersion}");
client.Timeout = TimeSpan.FromSeconds(10);

return client;
});
}

protected override void ConfigureAutofacServices(ContainerBuilder containerBuilder)
{
}
}
}
47 changes: 47 additions & 0 deletions src/Monitoring.RebootSearchInstance/MonitorConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// 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 NuGet.Jobs.Montoring.PackageLag;

namespace NuGet.Monitoring.RebootSearchInstance
{
public class MonitorConfiguration : SearchServiceConfiguration
{
public string FeedUrl { get; set; }
public string Role { get; set; }
public string RoleInstanceFormat { get; set; }

/// <summary>
/// This configuration is in seconds to match the monitor configuration. If the search instance lag is less
/// than this duration, that instance is considered healthy.
/// </summary>
public int HealthyThresholdInSeconds { get; set; }

/// <summary>
/// This configuration is in seconds to match the monitor configuration. If the search instance lag is more
/// than this duration, that instance is considered unhealthy.
/// </summary>
public int UnhealthyThresholdInSeconds { get; set; }

/// <summary>
/// The time to wait for a restarted instance to become healthy before moving on.
/// </summary>
public TimeSpan WaitForHealthyDuration { get; set; }

/// <summary>
/// The time to wait before checking a region for unhealthy instances again.
/// </summary>
public TimeSpan SleepDuration { get; set; }

/// <summary>
/// How long the process should run before ending (allowing the caller to restart the process as desired).
/// </summary>
public TimeSpan ProcessLifetime { get; set; }

/// <summary>
/// How frequently to poll an instance that was just restarted to check for it's new health status.
/// </summary>
public TimeSpan InstancePollFrequency { get; set; }
}
}
Loading

0 comments on commit 06270fc

Please sign in to comment.