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

Status aggregator job #494

Merged
merged 53 commits into from
Jul 30, 2018
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
e4d0f86
doesn't make messages yet
Jun 27, 2018
b318dbe
Merge branch 'dev' of https://github.com/NuGet/NuGet.Jobs into sb-icm
Jun 27, 2018
03c1478
add messaging
Jun 27, 2018
d27b115
export simple blob
Jun 28, 2018
d828566
reorganized status classes
Jun 30, 2018
822f756
refactor classes add test project
Jul 3, 2018
7a96990
remove servercommon classes, add some tests
Jul 13, 2018
fd8d8ce
fixed bugs and configured deployment
Jul 13, 2018
0eaf2ec
add statusaggregator to build scripts
Jul 13, 2018
04dbf01
sign status aggregator
Jul 13, 2018
8b5e98f
fix containername in script
Jul 13, 2018
69dab67
add missing caret
Jul 14, 2018
cb04d65
get certificate from keyvault
Jul 14, 2018
ceea509
exporter fixes
Jul 16, 2018
8de4d99
disable flaky test
Jul 16, 2018
ec75f37
fix messagings and export logic
Jul 16, 2018
aaadf93
"thank you for your patience"
Jul 16, 2018
a13521d
revert applicationhost.config changes
Jul 16, 2018
71e6ea4
integrate with pingdom
Jul 17, 2018
c60ffbf
add messaging for other types of events
Jul 18, 2018
b3b296e
check that event has no messages before writing first message
Jul 18, 2018
1e9ec04
minor fixes
Jul 20, 2018
de5f189
fix script to mirror variable name change
Jul 20, 2018
910b151
fix OutdatedRegionalSearchServiceInstanceIncidentParser
Jul 20, 2018
5fa8140
use shared table classes
Jul 23, 2018
f647d82
increase nuget.services.status reference
Jul 23, 2018
5328acf
use shared incident api library
Jul 24, 2018
a884640
increase to correct version of incident api
Jul 24, 2018
f8e3240
logging, comments, di
Jul 25, 2018
10e159a
reduce logger scope api
Jul 25, 2018
b90c7ff
small improvement to eventupdater and incidentupdater apis
Jul 25, 2018
e7f521c
fix logger extensions for null scope
Jul 25, 2018
8ac1129
remove unused usings in status aggregator config
Jul 25, 2018
cb19be4
add copyright
Jul 25, 2018
3903029
Merge branch 'dev' of https://github.com/NuGet/NuGet.Jobs into sb-icm
Jul 25, 2018
5ed8519
remove accidentally added usings
Jul 25, 2018
922ff50
add time thresholds in configuration
Jul 25, 2018
20a2fd6
fix tests
Jul 25, 2018
ae08323
use latest server common libraries
Jul 25, 2018
23302bd
remove unnecessary skip test
Jul 25, 2018
ba9646d
improve cursor logging
Jul 25, 2018
358ce1d
fix tests packages
Jul 25, 2018
b18d942
Merge branch 'dev' of https://github.com/NuGet/NuGet.Jobs into sb-icm
Jul 25, 2018
9957520
remove unnecessary whitespace change
Jul 25, 2018
97ae116
regex compliancy
Jul 27, 2018
40e34cd
other pr fixes
Jul 27, 2018
83d18a9
simplify message logic
Jul 27, 2018
fd67157
argument null exception
Jul 27, 2018
4dd7933
remove try get enum
Jul 30, 2018
e6fbbdf
Merge branch 'dev' into sb-icm
Jul 30, 2018
287ea8b
add back statusaggregator tests
Jul 30, 2018
33e8f41
this one's for u loic
Jul 30, 2018
33bce66
move incident title log to scope
Jul 30, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions NuGet.Jobs.sln
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Validation.Common.Job", "sr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PackageHash", "src\PackageHash\PackageHash.csproj", "{40843020-6F0A-48F0-AC28-42FFE3A5C21E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusAggregator", "src\StatusAggregator\StatusAggregator.csproj", "{D357FDB5-BF19-41A5-82B0-14C8CEC2A5EB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Validation.Common.Job.Tests", "tests\Validation.Common.Job.Tests\Validation.Common.Job.Tests.csproj", "{430F63C7-20C2-4872-AC3E-DDE846E50AA4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Validation.PackageSigning.ProcessSignature", "src\Validation.PackageSigning.ProcessSignature\Validation.PackageSigning.ProcessSignature.csproj", "{DD043977-6BCD-475A-BEE2-8C34309EC622}"
Expand Down Expand Up @@ -135,6 +137,8 @@ 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}") = "StatusAggregator.Tests", "tests\StatusAggregator.Tests\StatusAggregator.Tests.csproj", "{784F938D-4142-4C1C-B654-0978FEAD1731}"
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}"
Expand Down Expand Up @@ -305,6 +309,10 @@ Global
{40843020-6F0A-48F0-AC28-42FFE3A5C21E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40843020-6F0A-48F0-AC28-42FFE3A5C21E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40843020-6F0A-48F0-AC28-42FFE3A5C21E}.Release|Any CPU.Build.0 = Release|Any CPU
{D357FDB5-BF19-41A5-82B0-14C8CEC2A5EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D357FDB5-BF19-41A5-82B0-14C8CEC2A5EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D357FDB5-BF19-41A5-82B0-14C8CEC2A5EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D357FDB5-BF19-41A5-82B0-14C8CEC2A5EB}.Release|Any CPU.Build.0 = Release|Any CPU
{430F63C7-20C2-4872-AC3E-DDE846E50AA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{430F63C7-20C2-4872-AC3E-DDE846E50AA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{430F63C7-20C2-4872-AC3E-DDE846E50AA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -357,6 +365,10 @@ 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
{784F938D-4142-4C1C-B654-0978FEAD1731}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{784F938D-4142-4C1C-B654-0978FEAD1731}.Debug|Any CPU.Build.0 = Debug|Any CPU
{784F938D-4142-4C1C-B654-0978FEAD1731}.Release|Any CPU.ActiveCfg = Release|Any CPU
{784F938D-4142-4C1C-B654-0978FEAD1731}.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
Expand Down Expand Up @@ -413,6 +425,7 @@ Global
{B4B7564A-965B-447B-927F-6749E2C08880} = {6A776396-02B1-475D-A104-26940ADB04AB}
{FA87D075-A934-4443-8D0B-5DB32640B6D7} = {678D7B14-F8BC-4193-99AF-2EE8AA390A02}
{40843020-6F0A-48F0-AC28-42FFE3A5C21E} = {FA5644B5-4F08-43F6-86B3-039374312A47}
{D357FDB5-BF19-41A5-82B0-14C8CEC2A5EB} = {FA5644B5-4F08-43F6-86B3-039374312A47}
{430F63C7-20C2-4872-AC3E-DDE846E50AA4} = {6A776396-02B1-475D-A104-26940ADB04AB}
{DD043977-6BCD-475A-BEE2-8C34309EC622} = {678D7B14-F8BC-4193-99AF-2EE8AA390A02}
{ED2D370C-D921-433A-A0B9-A601F936EDD3} = {FA5644B5-4F08-43F6-86B3-039374312A47}
Expand All @@ -426,6 +439,7 @@ 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}
{784F938D-4142-4C1C-B654-0978FEAD1731} = {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}
Expand Down
2 changes: 2 additions & 0 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ Invoke-BuildStep 'Set version metadata in AssemblyInfo.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\StatusAggregator\Properties\AssemblyInfo.g.cs",
"$PSScriptRoot\src\Validation.Symbols.Core\Properties\AssemblyInfo.g.cs",
"$PSScriptRoot\src\Monitoring.RebootSearchInstance\Properties\AssemblyInfo.g.cs"

Expand Down Expand Up @@ -176,6 +177,7 @@ Invoke-BuildStep 'Creating artifacts' {
"src/Validation.PackageSigning.ValidateCertificate/Validation.PackageSigning.ValidateCertificate.csproj", `
"src/Validation.PackageSigning.RevalidateCertificate/Validation.PackageSigning.RevalidateCertificate.csproj", `
"src/PackageLagMonitor/Monitoring.PackageLag.csproj", `
"src/StatusAggregator/StatusAggregator.csproj", `
"src/Validation.Symbols.Core/Validation.Symbols.Core.csproj", `
"src/Monitoring.RebootSearchInstance/Monitoring.RebootSearchInstance.csproj" `
+ $ProjectsWithSymbols
Expand Down
13 changes: 13 additions & 0 deletions src/NuGet.Jobs.Common/Configuration/JobArgumentNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ public static class JobArgumentNames
public const string MailFrom = "MailFrom";
public const string SmtpUri = "SmtpUri";

// Arguments specific to StatusAggregator
public const string StatusStorageAccount = "StatusStorageAccount";
public const string StatusContainerName = "StatusContainerName";
public const string StatusTableName = "StatusTableName";
public const string StatusEnvironment = "StatusEnvironment";
public const string StatusMaximumSeverity = "StatusMaximumSeverity";
public const string StatusIncidentApiBaseUri = "StatusIncidentApiBaseUri";
public const string StatusIncidentApiCertificate = "StatusIncidentApiCertificate";
public const string StatusIncidentApiTeamId = "StatusIncidentApiTeamId";
public const string StatusEventStartMessageDelayMinutes = "StatusEventStartMessageDelayMinutes";
public const string StatusEventEndDelayMinutes = "StatusEventEndDelayMinutes";
public const string StatusEventVisibilityPeriodDays = "StatusEventVisibilityPeriodDays";

// Arguments specific to Stats.AggregateCdnDownloadsInGallery
public static string BatchSleepSeconds = "BatchSleepSeconds";
}
Expand Down
10 changes: 9 additions & 1 deletion src/NuGet.Jobs.Common/Configuration/JobConfigurationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.ComponentModel.Design;
using System.Linq;
using Microsoft.Extensions.Logging;
using NuGet.Jobs.Extensions;
using NuGet.Services.Configuration;
using NuGet.Services.KeyVault;

Expand Down Expand Up @@ -126,6 +127,13 @@ public static bool TryGetBoolArgument(IDictionary<string, string> jobArgsDiction
return null;
}

public static T TryGetEnumArgument<T>(IDictionary<string, string> jobArgsDictionary, string argName, T defaultValue)
Copy link
Contributor

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?

Copy link
Author

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!

where T : struct
{
var argumentString = TryGetArgument(jobArgsDictionary, argName);
return !string.IsNullOrEmpty(argumentString) && Enum.TryParse(argumentString, out T result) ? result : defaultValue;
}

private static Dictionary<string, string> ReadCommandLineArguments(ILogger logger, string[] commandLineArgs)
{
var argsDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Expand Down Expand Up @@ -190,7 +198,7 @@ private static Dictionary<string, string> ReadCommandLineArguments(ILogger logge

private static IDictionary<string, string> InjectSecrets(IServiceContainer serviceContainer, Dictionary<string, string> argsDictionary)
{
var secretReaderFactory = (ISecretReaderFactory)serviceContainer.GetService(typeof(ISecretReaderFactory));
var secretReaderFactory = serviceContainer.GetService<ISecretReaderFactory>();

var secretReader = secretReaderFactory.CreateSecretReader(argsDictionary);
if (secretReader == null)
Expand Down
51 changes: 51 additions & 0 deletions src/NuGet.Jobs.Common/Extensions/LoggerExtensions.cs
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
Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BeginScope on its own doesn't log a message when entering and leaving scope. This method does.

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;
}
}
}
}
}
12 changes: 12 additions & 0 deletions src/NuGet.Jobs.Common/Extensions/ServiceProviderExtensions.cs
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetService [](start = 24, length = 10)

This already exists: GetRequiredService<T>

Copy link
Author

Choose a reason for hiding this comment

The 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));
}
}
}
2 changes: 2 additions & 0 deletions src/NuGet.Jobs.Common/NuGet.Jobs.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
<Compile Include="Configuration\ServiceBusConfiguration.cs" />
<Compile Include="Configuration\ValidationDbConfiguration.cs" />
<Compile Include="Configuration\ValidationStorageConfiguration.cs" />
<Compile Include="Extensions\LoggerExtensions.cs" />
<Compile Include="Extensions\ServiceProviderExtensions.cs" />
<Compile Include="Extensions\SqlConnectionStringBuilderExtensions.cs" />
<Compile Include="Extensions\XElementExtensions.cs" />
<Compile Include="SecretReader\ISecretReaderFactory.cs" />
Expand Down
93 changes: 93 additions & 0 deletions src/StatusAggregator/ComponentFactory.cs
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comments. What is a Component?

Copy link
Author

Choose a reason for hiding this comment

The 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")
});
}
}
}
60 changes: 60 additions & 0 deletions src/StatusAggregator/Cursor.cs
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StatusAggregator [](start = 10, length = 16)

There's two empty lines above this one

Copy link
Author

Choose a reason for hiding this comment

The 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;
Copy link
Contributor

@loic-sharma loic-sharma Jul 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

table [](start = 21, length = 5)

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);
Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Author

Choose a reason for hiding this comment

The 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.

Copy link
Author

Choose a reason for hiding this comment

The 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.");
}
Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Author

Choose a reason for hiding this comment

The 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this table thread safe? Does it need to be thread safe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add comments to this either way.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's Azure table storage, which is thread safe.

}
}
}
}
Loading