-
Notifications
You must be signed in to change notification settings - Fork 21
Status aggregator job #494
Changes from 44 commits
e4d0f86
b318dbe
03c1478
d27b115
d828566
822f756
7a96990
fd8d8ce
0eaf2ec
04dbf01
8b5e98f
69dab67
cb04d65
ceea509
8de4d99
ec75f37
aaadf93
a13521d
71e6ea4
c60ffbf
b3b296e
1e9ec04
de5f189
910b151
5fa8140
f647d82
5328acf
a884640
f8e3240
10e159a
b90c7ff
e7f521c
8ac1129
cb19be4
3903029
5ed8519
922ff50
20a2fd6
ae08323
23302bd
ba9646d
358ce1d
b18d942
9957520
97ae116
40e34cd
83d18a9
fd67157
4dd7933
e6fbbdf
287ea8b
33e8f41
33bce66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// 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 Microsoft.Extensions.Logging; | ||
using System; | ||
|
||
namespace NuGet.Jobs.Extensions | ||
{ | ||
public static class LoggerExtensions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comments. Why the current login is not enough? Why this method should be used over other methods? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Will add comments. |
||
{ | ||
public static IDisposable Scope( | ||
this ILogger logger, | ||
string message, | ||
params object[] args) | ||
{ | ||
return new LoggerScopeHelper(logger, message, args); | ||
} | ||
|
||
private class LoggerScopeHelper : IDisposable | ||
{ | ||
private readonly ILogger _logger; | ||
private readonly IDisposable _scope; | ||
|
||
private readonly string _message; | ||
private readonly object[] _args; | ||
|
||
private bool _isDisposed = false; | ||
|
||
public LoggerScopeHelper( | ||
ILogger logger, string message, object[] args) | ||
{ | ||
_logger = logger; | ||
_message = message; | ||
_args = args; | ||
|
||
_scope = logger.BeginScope(_message, _args); | ||
_logger.LogInformation("Entering scope: " + _message, _args); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
if (!_isDisposed) | ||
{ | ||
_logger.LogInformation("Leaving scope: " + _message, _args); | ||
_scope?.Dispose(); // ILogger can return a null scope (most notably during testing with a Mock<ILogger>) | ||
_isDisposed = true; | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System; | ||
|
||
namespace NuGet.Jobs.Extensions | ||
{ | ||
public static class ServiceProviderExtensions | ||
{ | ||
public static T GetService<T>(this IServiceProvider provider) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This already exists: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed and replaced the uses of this new extension |
||
{ | ||
return (T)provider.GetService(typeof(T)); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// 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 NuGet.Services.Status; | ||
|
||
namespace StatusAggregator | ||
{ | ||
public static class ComponentFactory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comments. What is a Component? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NuGet/ServerCommon#170 for more context. I agree that this class should have more comments however. |
||
{ | ||
public const string RootName = "NuGet"; | ||
public const string GalleryName = "NuGet.org"; | ||
public const string RestoreName = "Restore"; | ||
public const string SearchName = "Search"; | ||
public const string UploadName = "Package Publishing"; | ||
|
||
public const string V2ProtocolName = "V2 Protocol"; | ||
public const string V3ProtocolName = "V3 Protocol"; | ||
|
||
public const string GlobalRegionName = "Global"; | ||
public const string ChinaRegionName = "China"; | ||
|
||
public const string UsncInstanceName = "North Central US"; | ||
public const string UsscInstanceName = "South Central US"; | ||
public const string EaInstanceName = "East Asia"; | ||
public const string SeaInstanceName = "Southeast Asia"; | ||
|
||
/// <summary> | ||
/// Creates the NuGet service root component. | ||
/// </summary> | ||
public static IComponent CreateNuGetServiceRootComponent() | ||
{ | ||
return new TreeComponent( | ||
RootName, | ||
"", | ||
new IComponent[] | ||
{ | ||
new PrimarySecondaryComponent( | ||
GalleryName, | ||
"Browsing the Gallery website", | ||
new[] | ||
{ | ||
new LeafComponent(UsncInstanceName, "Primary region"), | ||
new LeafComponent(UsscInstanceName, "Backup region") | ||
}), | ||
new TreeComponent( | ||
RestoreName, | ||
"Downloading and installing packages from NuGet", | ||
new IComponent[] | ||
{ | ||
new TreeComponent( | ||
V3ProtocolName, | ||
"Restore using the V3 API", | ||
new[] | ||
{ | ||
new LeafComponent(GlobalRegionName, "V3 restore for users outside of China"), | ||
new LeafComponent(ChinaRegionName, "V3 restore for users inside China") | ||
}), | ||
new PrimarySecondaryComponent( | ||
V2ProtocolName, | ||
"Restore using the V2 API", | ||
new[] | ||
{ | ||
new LeafComponent(UsncInstanceName, "Primary region"), | ||
new LeafComponent(UsscInstanceName, "Backup region") | ||
}) | ||
}), | ||
new TreeComponent( | ||
SearchName, | ||
"Searching for new and existing packages in Visual Studio or the Gallery website", | ||
new[] | ||
{ | ||
new PrimarySecondaryComponent( | ||
GlobalRegionName, | ||
"Search for packages outside China", | ||
new[] | ||
{ | ||
new LeafComponent(UsncInstanceName, "Primary region"), | ||
new LeafComponent(UsscInstanceName, "Backup region") | ||
}), | ||
new PrimarySecondaryComponent( | ||
ChinaRegionName, | ||
"Search for packages inside China", | ||
new[] | ||
{ | ||
new LeafComponent(EaInstanceName, "Primary region"), | ||
new LeafComponent(SeaInstanceName, "Backup region") | ||
}) | ||
}), | ||
new LeafComponent(UploadName, "Uploading new packages to NuGet.org") | ||
}); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// 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; | ||
using Microsoft.Extensions.Logging; | ||
using NuGet.Jobs.Extensions; | ||
using NuGet.Services.Status.Table; | ||
using StatusAggregator.Table; | ||
|
||
|
||
namespace StatusAggregator | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There's two empty lines above this one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch! |
||
{ | ||
public class Cursor : ICursor | ||
{ | ||
public Cursor( | ||
ITableWrapper table, | ||
ILogger<Cursor> logger) | ||
{ | ||
_table = table; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I would add null checks to all constructors. From my experience, it makes catching null reference exceptions easier :) |
||
_logger = logger; | ||
} | ||
|
||
private readonly ITableWrapper _table; | ||
|
||
private readonly ILogger<Cursor> _logger; | ||
|
||
public async Task<DateTime> Get() | ||
{ | ||
using (_logger.Scope("Fetching cursor.")) | ||
{ | ||
var cursor = await _table.Retrieve<CursorEntity>( | ||
CursorEntity.DefaultPartitionKey, CursorEntity.DefaultRowKey); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it ok to get a null cursor back? Should it throw instead of setting to minvalue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there's no cursor, it likely means the table is empty and this is the first time the job has been run. So it should start at the beginning of time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll add a comment to make this behavior clearer. |
||
|
||
DateTime value; | ||
if (cursor == null) | ||
{ | ||
value = DateTime.MinValue; | ||
_logger.LogInformation("Could not fetch cursor."); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not super clear from this log that the cursor will be set to the beginning of time. Maybe log the value here? Feel free to ignore There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll add that to the log |
||
else | ||
{ | ||
value = cursor.Value; | ||
_logger.LogInformation("Fetched cursor with value {Cursor}.", value); | ||
} | ||
|
||
return value; | ||
} | ||
} | ||
|
||
public Task Set(DateTime value) | ||
{ | ||
using (_logger.Scope("Updating cursor to {Cursor}.", value)) | ||
{ | ||
var cursorEntity = new CursorEntity(value); | ||
return _table.InsertOrReplaceAsync(cursorEntity); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this table thread safe? Does it need to be thread safe? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comments to this either way. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's Azure table storage, which is thread safe. |
||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this method used anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added it initially, must have removed it. Great catch!