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

Commit c6bd2f6

Browse files
author
Scott Bommarito
authored
Make CreateAzureCdnWarehouseReports SQL timeout configurable (#283)
1 parent 792f5a3 commit c6bd2f6

3 files changed

Lines changed: 28 additions & 23 deletions

File tree

src/Stats.CreateAzureCdnWarehouseReports/Job.cs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace Stats.CreateAzureCdnWarehouseReports
1717
public class Job
1818
: JobBase
1919
{
20+
private const int DefaultSqlCommandTimeout = 1800; // 30 minute SQL command timeout by default
2021
private const string _recentPopularityDetailByPackageReportBaseName = "recentpopularitydetail_";
2122
private CloudStorageAccount _cloudStorageAccount;
2223
private CloudStorageAccount _dataStorageAccount;
@@ -25,6 +26,7 @@ public class Job
2526
private SqlConnectionStringBuilder _galleryDatabase;
2627
private string _reportName;
2728
private string[] _dataContainerNames;
29+
private int _sqlCommandTimeout = DefaultSqlCommandTimeout;
2830

2931
private static readonly IDictionary<string, string> _storedProcedures = new Dictionary<string, string>
3032
{
@@ -48,6 +50,7 @@ public override void Init(IDictionary<string, string> jobArgsDictionary)
4850
var statisticsDatabaseConnectionString = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.StatisticsDatabase);
4951
var galleryDatabaseConnectionString = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.SourceDatabase);
5052
var dataStorageAccountConnectionString = JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.DataStorageAccount);
53+
_sqlCommandTimeout = JobConfigurationManager.TryGetIntArgument(jobArgsDictionary, JobArgumentNames.CommandTimeOut) ?? DefaultSqlCommandTimeout;
5154

5255
_cloudStorageAccount = ValidateAzureCloudStorageAccount(cloudStorageAccountConnectionString, JobArgumentNames.AzureCdnCloudStorageAccount);
5356
_statisticsContainerName = ValidateAzureContainerName(JobConfigurationManager.GetArgument(jobArgsDictionary, JobArgumentNames.AzureCdnCloudStorageContainerName), JobArgumentNames.AzureCdnCloudStorageContainerName);
@@ -81,12 +84,12 @@ public override async Task Run()
8184
// generate all reports
8285
var reportGenerators = new Dictionary<ReportBuilder, ReportDataCollector>
8386
{
84-
{ new ReportBuilder(reportBuilderLogger, ReportNames.NuGetClientVersion), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.NuGetClientVersion], _statisticsDatabase) },
85-
{ new ReportBuilder(reportBuilderLogger, ReportNames.Last6Weeks), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.Last6Weeks], _statisticsDatabase) },
86-
{ new ReportBuilder(reportBuilderLogger, ReportNames.RecentCommunityPopularity), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.RecentCommunityPopularity], _statisticsDatabase) },
87-
{ new ReportBuilder(reportBuilderLogger, ReportNames.RecentCommunityPopularityDetail), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.RecentCommunityPopularityDetail], _statisticsDatabase) },
88-
{ new ReportBuilder(reportBuilderLogger, ReportNames.RecentPopularity), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.RecentPopularity], _statisticsDatabase) },
89-
{ new ReportBuilder(reportBuilderLogger, ReportNames.RecentPopularityDetail), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.RecentPopularityDetail], _statisticsDatabase) }
87+
{ new ReportBuilder(reportBuilderLogger, ReportNames.NuGetClientVersion), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.NuGetClientVersion], _statisticsDatabase, _sqlCommandTimeout) },
88+
{ new ReportBuilder(reportBuilderLogger, ReportNames.Last6Weeks), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.Last6Weeks], _statisticsDatabase, _sqlCommandTimeout) },
89+
{ new ReportBuilder(reportBuilderLogger, ReportNames.RecentCommunityPopularity), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.RecentCommunityPopularity], _statisticsDatabase, _sqlCommandTimeout) },
90+
{ new ReportBuilder(reportBuilderLogger, ReportNames.RecentCommunityPopularityDetail), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.RecentCommunityPopularityDetail], _statisticsDatabase, _sqlCommandTimeout) },
91+
{ new ReportBuilder(reportBuilderLogger, ReportNames.RecentPopularity), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.RecentPopularity], _statisticsDatabase, _sqlCommandTimeout) },
92+
{ new ReportBuilder(reportBuilderLogger, ReportNames.RecentPopularityDetail), new ReportDataCollector(reportCollectorLogger, _storedProcedures[ReportNames.RecentPopularityDetail], _statisticsDatabase, _sqlCommandTimeout) }
9093
};
9194

9295
foreach (var reportGenerator in reportGenerators)
@@ -102,7 +105,7 @@ public override async Task Run()
102105
{
103106
// generate only the specific report
104107
var reportBuilder = new ReportBuilder(reportBuilderLogger, _reportName);
105-
var reportDataCollector = new ReportDataCollector(reportCollectorLogger, _storedProcedures[_reportName], _statisticsDatabase);
108+
var reportDataCollector = new ReportDataCollector(reportCollectorLogger, _storedProcedures[_reportName], _statisticsDatabase, _sqlCommandTimeout);
106109

107110
await ProcessReport(LoggerFactory, destinationContainer, reportBuilder, reportDataCollector, reportGenerationTime);
108111
}
@@ -162,14 +165,14 @@ private static async Task ProcessReport(ILoggerFactory loggerFactory, CloudBlobC
162165

163166
private async Task RebuildPackageReports(CloudBlobContainer destinationContainer, DateTime reportGenerationTime)
164167
{
165-
var dirtyPackageIds = await ReportDataCollector.GetDirtyPackageIds(LoggerFactory.CreateLogger<ReportDataCollector>(), _statisticsDatabase, reportGenerationTime);
168+
var dirtyPackageIds = await ReportDataCollector.GetDirtyPackageIds(LoggerFactory.CreateLogger<ReportDataCollector>(), _statisticsDatabase, reportGenerationTime, _sqlCommandTimeout);
166169

167170
if (!dirtyPackageIds.Any())
168171
return;
169172

170173
// first process the top 100 packages
171174
var top100 = dirtyPackageIds.Take(100);
172-
var reportDataCollector = new ReportDataCollector(LoggerFactory.CreateLogger<ReportDataCollector>(), _storedProceduresPerPackageId[ReportNames.RecentPopularityDetailByPackageId], _statisticsDatabase);
175+
var reportDataCollector = new ReportDataCollector(LoggerFactory.CreateLogger<ReportDataCollector>(), _storedProceduresPerPackageId[ReportNames.RecentPopularityDetailByPackageId], _statisticsDatabase, _sqlCommandTimeout);
173176
var top100Task = Parallel.ForEach(top100, new ParallelOptions { MaxDegreeOfParallelism = 4 }, dirtyPackageId =>
174177
{
175178
var packageId = dirtyPackageId.PackageId.ToLowerInvariant();
@@ -199,7 +202,8 @@ private async Task RebuildPackageReports(CloudBlobContainer destinationContainer
199202
new ReportDataCollector(
200203
LoggerFactory.CreateLogger<ReportDataCollector>(),
201204
_storedProceduresPerPackageId[ReportNames.RecentPopularityDetailByPackageId],
202-
_statisticsDatabase)
205+
_statisticsDatabase,
206+
_sqlCommandTimeout)
203207
}
204208
};
205209

@@ -215,15 +219,15 @@ private async Task RebuildPackageReports(CloudBlobContainer destinationContainer
215219
if (top100Task.IsCompleted)
216220
{
217221
var runToCursor = dirtyPackageIds.First().RunToCuror;
218-
await ReportDataCollector.UpdateDirtyPackageIdCursor(_statisticsDatabase, runToCursor);
222+
await ReportDataCollector.UpdateDirtyPackageIdCursor(_statisticsDatabase, runToCursor, _sqlCommandTimeout);
219223
}
220224
}
221225
}
222226

223227
private async Task CleanInactiveRecentPopularityDetailByPackageReports(CloudBlobContainer destinationContainer, DateTime reportGenerationTime)
224228
{
225229
Logger.LogDebug("Getting list of inactive packages.");
226-
var packageIds = await ReportDataCollector.ListInactivePackageIdReports(_statisticsDatabase, reportGenerationTime);
230+
var packageIds = await ReportDataCollector.ListInactivePackageIdReports(_statisticsDatabase, reportGenerationTime, _sqlCommandTimeout);
227231
Logger.LogInformation("Found {InactivePackageCount} inactive packages.", packageIds.Count);
228232

229233
// Collect the list of reports

src/Stats.CreateAzureCdnWarehouseReports/ReportDataCollector.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,18 @@ namespace Stats.CreateAzureCdnWarehouseReports
1313
{
1414
internal class ReportDataCollector
1515
{
16-
private const int _commandTimeout = 1800; // 30 minutes max
16+
private int _commandTimeout;
1717
private readonly string _procedureName;
1818
private readonly SqlConnectionStringBuilder _sourceDatabase;
1919

2020
private ILogger<ReportDataCollector> _logger;
2121

22-
public ReportDataCollector(ILogger<ReportDataCollector> logger, string procedureName, SqlConnectionStringBuilder sourceDatabase)
22+
public ReportDataCollector(ILogger<ReportDataCollector> logger, string procedureName, SqlConnectionStringBuilder sourceDatabase, int timeout)
2323
{
2424
_logger = logger;
2525
_procedureName = procedureName;
2626
_sourceDatabase = sourceDatabase;
27+
_commandTimeout = timeout;
2728
}
2829

2930
public async Task<DataTable> CollectAsync(DateTime reportGenerationTime, params Tuple<string, int, string>[] parameters)
@@ -40,27 +41,27 @@ public async Task<DataTable> CollectAsync(DateTime reportGenerationTime, params
4041
return table;
4142
}
4243

43-
public static async Task<IReadOnlyCollection<DirtyPackageId>> GetDirtyPackageIds(ILogger logger, SqlConnectionStringBuilder sourceDatabase, DateTime reportGenerationTime)
44+
public static async Task<IReadOnlyCollection<DirtyPackageId>> GetDirtyPackageIds(ILogger logger, SqlConnectionStringBuilder sourceDatabase, DateTime reportGenerationTime, int commandTimeout)
4445
{
4546
logger.LogInformation("Getting list of dirty packages IDs.");
4647

4748
IReadOnlyCollection<DirtyPackageId> packageIds = new List<DirtyPackageId>();
4849

4950
// Get the data
50-
await WithRetry(async () => packageIds = await GetDirtyPackageIdsFromWarehouse(sourceDatabase, reportGenerationTime), logger);
51+
await WithRetry(async () => packageIds = await GetDirtyPackageIdsFromWarehouse(sourceDatabase, reportGenerationTime, commandTimeout), logger);
5152

5253
logger.LogInformation("Found {DirtyPackagesCount} dirty packages to update.", packageIds.Count);
5354

5455
return packageIds;
5556
}
5657

57-
public static async Task<IReadOnlyCollection<string>> ListInactivePackageIdReports(SqlConnectionStringBuilder sourceDatabase, DateTime reportGenerationTime)
58+
public static async Task<IReadOnlyCollection<string>> ListInactivePackageIdReports(SqlConnectionStringBuilder sourceDatabase, DateTime reportGenerationTime, int commandTimeout)
5859
{
5960
using (var connection = await sourceDatabase.ConnectTo())
6061
{
6162
var command = new SqlCommand("[dbo].[DownloadReportListInactive]", connection);
6263
command.CommandType = CommandType.StoredProcedure;
63-
command.CommandTimeout = _commandTimeout;
64+
command.CommandTimeout = commandTimeout;
6465

6566
command.Parameters.Add("ReportGenerationTime", SqlDbType.DateTime).Value = reportGenerationTime;
6667

@@ -132,13 +133,13 @@ private async Task<DataTable> ExecuteSql(DateTime reportGenerationTime, params T
132133
}
133134
}
134135

135-
private static async Task<IReadOnlyCollection<DirtyPackageId>> GetDirtyPackageIdsFromWarehouse(SqlConnectionStringBuilder sourceDatabase, DateTime reportGenerationTime)
136+
private static async Task<IReadOnlyCollection<DirtyPackageId>> GetDirtyPackageIdsFromWarehouse(SqlConnectionStringBuilder sourceDatabase, DateTime reportGenerationTime, int commandTimeout)
136137
{
137138
using (var connection = await sourceDatabase.ConnectTo())
138139
{
139140
var command = new SqlCommand("[dbo].[GetDirtyPackageIds]", connection);
140141
command.CommandType = CommandType.StoredProcedure;
141-
command.CommandTimeout = _commandTimeout;
142+
command.CommandTimeout = commandTimeout;
142143

143144
command.Parameters.Add("ReportGenerationTime", SqlDbType.DateTime).Value = reportGenerationTime;
144145

@@ -155,13 +156,13 @@ private static async Task<IReadOnlyCollection<DirtyPackageId>> GetDirtyPackageId
155156
}
156157
}
157158

158-
public static async Task UpdateDirtyPackageIdCursor(SqlConnectionStringBuilder sourceDatabase, DateTime runToCursor)
159+
public static async Task UpdateDirtyPackageIdCursor(SqlConnectionStringBuilder sourceDatabase, DateTime runToCursor, int commandTimeout)
159160
{
160161
using (var connection = await sourceDatabase.ConnectTo())
161162
{
162163
var command = new SqlCommand("[dbo].[UpdateDirtyPackageIdCursor]", connection);
163164
command.CommandType = CommandType.StoredProcedure;
164-
command.CommandTimeout = _commandTimeout;
165+
command.CommandTimeout = commandTimeout;
165166
command.Parameters.Add("@Position", SqlDbType.DateTime).Value = runToCursor;
166167

167168
await command.ExecuteNonQueryAsync();

src/Stats.CreateAzureCdnWarehouseReports/Scripts/Stats.CreateAzureCdnWarehouseReports.cmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ cd bin
77

88
title #{Jobs.stats.createazurecdnwarehousereports.Title}
99

10-
start /w stats.createazurecdnwarehousereports.exe -VaultName "#{Deployment.Azure.KeyVault.VaultName}" -ClientId "#{Deployment.Azure.KeyVault.ClientId}" -CertificateThumbprint "#{Deployment.Azure.KeyVault.CertificateThumbprint}" -AzureCdnCloudStorageAccount "#{Jobs.stats.createazurecdnwarehousereports.AzureCdn.CloudStorageAccount}" -AzureCdnCloudStorageContainerName "#{Jobs.stats.createazurecdnwarehousereports.AzureCdn.CloudStorageContainerName}" -StatisticsDatabase "#{Jobs.stats.createazurecdnwarehousereports.StatisticsDatabase}" -SourceDatabase "#{Jobs.stats.createazurecdnwarehousereports.SourceDatabase}" -DataStorageAccount "#{Jobs.stats.createazurecdnwarehousereports.DataStorageAccount}" -InstrumentationKey "#{Jobs.stats.createazurecdnwarehousereports.InstrumentationKey}" -DataContainerName "#{Jobs.stats.createazurecdnwarehousereports.DataContainerName}" -verbose true -Interval #{Jobs.stats.createazurecdnwarehousereports.Interval}
10+
start /w stats.createazurecdnwarehousereports.exe -VaultName "#{Deployment.Azure.KeyVault.VaultName}" -ClientId "#{Deployment.Azure.KeyVault.ClientId}" -CertificateThumbprint "#{Deployment.Azure.KeyVault.CertificateThumbprint}" -AzureCdnCloudStorageAccount "#{Jobs.stats.createazurecdnwarehousereports.AzureCdn.CloudStorageAccount}" -AzureCdnCloudStorageContainerName "#{Jobs.stats.createazurecdnwarehousereports.AzureCdn.CloudStorageContainerName}" -StatisticsDatabase "#{Jobs.stats.createazurecdnwarehousereports.StatisticsDatabase}" -SourceDatabase "#{Jobs.stats.createazurecdnwarehousereports.SourceDatabase}" -DataStorageAccount "#{Jobs.stats.createazurecdnwarehousereports.DataStorageAccount}" -InstrumentationKey "#{Jobs.stats.createazurecdnwarehousereports.InstrumentationKey}" -DataContainerName "#{Jobs.stats.createazurecdnwarehousereports.DataContainerName}" -CommandTimeOut "#{Jobs.stats.createazurecdnwarehousereports.CommandTimeOut}" -verbose true -Interval #{Jobs.stats.createazurecdnwarehousereports.Interval}
1111

1212
echo "Finished #{Jobs.stats.createazurecdnwarehousereports.Title}"
1313

0 commit comments

Comments
 (0)