Skip to content

Commit 7b30ebf

Browse files
StorageStatusService (#7165)
Gallery status service will verify the storage primary or secondary for status depending on the read only mode. The readOnly will verify the secondary storage and the readWrite will verify the primary storage.
1 parent c5befce commit 7b30ebf

10 files changed

Lines changed: 244 additions & 25 deletions

File tree

src/NuGetGallery.Core/Auditing/CloudAuditingService.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,14 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5-
using System.Collections.Generic;
65
using System.Globalization;
76
using System.IO;
8-
using System.Linq;
9-
using System.Reflection;
107
using System.Threading.Tasks;
118
using Microsoft.WindowsAzure.Storage;
129
using Microsoft.WindowsAzure.Storage.Blob;
1310
using Microsoft.WindowsAzure.Storage.Blob.Protocol;
1411
using Microsoft.WindowsAzure.Storage.RetryPolicies;
1512
using Newtonsoft.Json;
16-
using Newtonsoft.Json.Converters;
17-
using Newtonsoft.Json.Linq;
18-
using Newtonsoft.Json.Serialization;
1913
using NuGetGallery.Auditing.Obfuscation;
2014

2115
namespace NuGetGallery.Auditing
@@ -133,9 +127,9 @@ private static async Task WriteBlob(string auditData, string fullPath, CloudBloc
133127
}
134128
}
135129

136-
public Task<bool> IsAvailableAsync()
130+
public Task<bool> IsAvailableAsync(BlobRequestOptions options, OperationContext operationContext)
137131
{
138-
return _auditContainer.ExistsAsync();
132+
return _auditContainer.ExistsAsync(options, operationContext);
139133
}
140134

141135
public override string RenderAuditEntry(AuditEntry entry)

src/NuGetGallery.Core/ICloudStorageStatusDependency.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Threading.Tasks;
5+
using Microsoft.WindowsAzure.Storage;
6+
using Microsoft.WindowsAzure.Storage.Blob;
57

68
namespace NuGetGallery
79
{
@@ -11,6 +13,6 @@ namespace NuGetGallery
1113
/// </summary>
1214
public interface ICloudStorageStatusDependency
1315
{
14-
Task<bool> IsAvailableAsync();
16+
Task<bool> IsAvailableAsync(BlobRequestOptions options, OperationContext operationContext);
1517
}
1618
}

src/NuGetGallery.Core/Services/CloudBlobContainerWrapper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Threading.Tasks;
5+
using Microsoft.WindowsAzure.Storage;
56
using Microsoft.WindowsAzure.Storage.Blob;
67

78
namespace NuGetGallery
@@ -34,9 +35,9 @@ public ISimpleCloudBlob GetBlobReference(string blobAddressUri)
3435
return new CloudBlobWrapper(_blobContainer.GetBlockBlobReference(blobAddressUri));
3536
}
3637

37-
public Task<bool> ExistsAsync()
38+
public Task<bool> ExistsAsync(BlobRequestOptions blobRequestOptions, OperationContext context)
3839
{
39-
return _blobContainer.ExistsAsync();
40+
return _blobContainer.ExistsAsync(blobRequestOptions, context);
4041
}
4142

4243
public async Task<bool> DeleteIfExistsAsync()

src/NuGetGallery.Core/Services/ICloudBlobContainer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Threading.Tasks;
5+
using Microsoft.WindowsAzure.Storage;
56
using Microsoft.WindowsAzure.Storage.Blob;
67

78
namespace NuGetGallery
@@ -11,7 +12,7 @@ public interface ICloudBlobContainer
1112
Task CreateIfNotExistAsync();
1213
Task SetPermissionsAsync(BlobContainerPermissions permissions);
1314
ISimpleCloudBlob GetBlobReference(string blobAddressUri);
14-
Task<bool> ExistsAsync();
15+
Task<bool> ExistsAsync(BlobRequestOptions options, OperationContext operationContext);
1516
Task<bool> DeleteIfExistsAsync();
1617
Task CreateAsync();
1718
}

src/NuGetGallery/App_Start/DefaultDependenciesModule.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,14 +863,15 @@ private static void ConfigureForAzureStorage(ContainerBuilder builder, IGalleryC
863863
.SingleInstance()
864864
.Keyed<ICloudBlobClient>(dependent.BindingKey);
865865

866+
// Do not register the service as ICloudStorageStatusDependency because
867+
// the CloudAuditingService registers it and the gallery uses the same storage account for all the containers.
866868
builder.RegisterType<CloudBlobFileStorageService>()
867869
.WithParameter(new ResolvedParameter(
868870
(pi, ctx) => pi.ParameterType == typeof(ICloudBlobClient),
869871
(pi, ctx) => ctx.ResolveKeyed<ICloudBlobClient>(dependent.BindingKey)))
870872
.AsSelf()
871873
.As<IFileStorageService>()
872874
.As<ICoreFileStorageService>()
873-
.As<ICloudStorageStatusDependency>()
874875
.SingleInstance()
875876
.Keyed<IFileStorageService>(dependent.BindingKey);
876877
}
@@ -902,7 +903,6 @@ private static void ConfigureForAzureStorage(ContainerBuilder builder, IGalleryC
902903
builder.RegisterInstance(new CloudReportService(configuration.Current.AzureStorage_Statistics_ConnectionString, configuration.Current.AzureStorageReadAccessGeoRedundant))
903904
.AsSelf()
904905
.As<IReportService>()
905-
.As<ICloudStorageStatusDependency>()
906906
.SingleInstance();
907907

908908
// when running on Windows Azure, download counts come from the downloads.v1.json blob

src/NuGetGallery/Services/CloudBlobFileStorageService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace NuGetGallery
1313
{
14-
public class CloudBlobFileStorageService : CloudBlobCoreFileStorageService, IFileStorageService, ICloudStorageStatusDependency
14+
public class CloudBlobFileStorageService : CloudBlobCoreFileStorageService, IFileStorageService
1515
{
1616
private readonly IAppConfiguration _configuration;
1717
private readonly ISourceDestinationRedirectPolicy _redirectPolicy;
@@ -98,7 +98,7 @@ internal Uri GetRedirectUri(Uri requestUrl, Uri blobUri)
9898
public async Task<bool> IsAvailableAsync()
9999
{
100100
var container = await GetContainerAsync(CoreConstants.Folders.PackagesFolderName);
101-
return await container.ExistsAsync();
101+
return await container.ExistsAsync(options: null, operationContext: null);
102102
}
103103
}
104104
}

src/NuGetGallery/Services/CloudReportService.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace NuGetGallery
1010
{
11-
public class CloudReportService : IReportService, ICloudStorageStatusDependency
11+
public class CloudReportService : IReportService
1212
{
1313
private const string _statsContainerName = "nuget-cdnstats";
1414
private readonly string _connectionString;
@@ -20,12 +20,6 @@ public CloudReportService(string connectionString, bool readAccessGeoRedundant)
2020
_readAccessGeoRedundant = readAccessGeoRedundant;
2121
}
2222

23-
public Task<bool> IsAvailableAsync()
24-
{
25-
var container = GetCloudBlobContainer();
26-
return container.ExistsAsync();
27-
}
28-
2923
public async Task<StatisticsReport> Load(string reportName)
3024
{
3125
// In NuGet we always use lowercase names for all blobs in Azure Storage

src/NuGetGallery/Services/StatusService.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
using System.Net.Http;
1111
using System.Threading.Tasks;
1212
using System.Web.Mvc;
13+
using Microsoft.WindowsAzure.Storage.Blob;
14+
using Microsoft.WindowsAzure.Storage.RetryPolicies;
1315
using NuGetGallery.Configuration;
1416
using NuGetGallery.Helpers;
1517

@@ -80,7 +82,7 @@ private bool IsSqlAzureAvailable()
8082
return sqlAzureAvailable;
8183
}
8284

83-
private async Task<bool?> IsAzureStorageAvailable()
85+
internal async Task<bool?> IsAzureStorageAvailable()
8486
{
8587
if (_config == null || _config.StorageType != StorageType.AzureStorage)
8688
{
@@ -91,7 +93,12 @@ private bool IsSqlAzureAvailable()
9193
try
9294
{
9395
// Check Storage Availability
94-
var tasks = _cloudStorageAvailabilityChecks.Select(s => s.IsAvailableAsync());
96+
BlobRequestOptions options = new BlobRequestOptions();
97+
// Used the LocationMode.SecondaryOnly and not PrimaryThenSecondary for two reasons:
98+
// 1. When the primary is down and secondary is up if PrimaryThenSecondary is used there will be an extra and not needed call to the primary.
99+
// 2. When the primary is up the secondary status check will return the primary status instead of secondary.
100+
options.LocationMode = _config.ReadOnlyMode ? LocationMode.SecondaryOnly : LocationMode.PrimaryOnly;
101+
var tasks = _cloudStorageAvailabilityChecks.Select(s => s.IsAvailableAsync(options, operationContext : null));
95102
var eachAvailable = await Task.WhenAll(tasks);
96103
storageAvailable = eachAvailable.All(a => a);
97104
}

tests/NuGetGallery.Facts/NuGetGallery.Facts.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
<Compile Include="Infrastructure\Lucene\GallerySearchServiceFacts.cs" />
9090
<Compile Include="Helpers\StreamHelperFacts.cs" />
9191
<Compile Include="Services\PackageDeprecationServiceFacts.cs" />
92+
<Compile Include="Services\StatusServiceFacts.cs" />
9293
<Compile Include="TestData\TestDataResourceUtility.cs" />
9394
<Compile Include="UsernameValidationRegex.cs" />
9495
<Compile Include="Extensions\NumberExtensionsFacts.cs" />

0 commit comments

Comments
 (0)