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

Commit 5f99bbd

Browse files
author
Scott Bommarito
authored
StatusAggregator should handle incident ingestion failures gracefully (#671)
1 parent 297a5cf commit 5f99bbd

10 files changed

Lines changed: 298 additions & 21 deletions

File tree

src/StatusAggregator/Export/IStatusSerializer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ namespace StatusAggregator.Export
1111
public interface IStatusSerializer
1212
{
1313
/// <summary>
14-
/// Serializes <paramref name="rootComponent"/> and <paramref name="recentEvents"/> and saves to storage with a time of <paramref name="cursor"/>.
14+
/// Serializes <paramref name="rootComponent"/> and <paramref name="recentEvents"/> and saves to storage with a last built time of <paramref name="lastBuilt"/> and a last updated time of <paramref name="lastUpdated"/>.
1515
/// </summary>
16-
Task Serialize(DateTime cursor, IComponent rootComponent, IEnumerable<Event> recentEvents);
16+
Task Serialize(DateTime lastBuilt, DateTime lastUpdated, IComponent rootComponent, IEnumerable<Event> recentEvents);
1717
}
1818
}

src/StatusAggregator/Export/StatusExporter.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,43 @@
55
using System.Threading.Tasks;
66
using Microsoft.Extensions.Logging;
77
using NuGet.Jobs.Extensions;
8+
using StatusAggregator.Collector;
9+
using StatusAggregator.Update;
810

911
namespace StatusAggregator.Export
1012
{
1113
public class StatusExporter : IStatusExporter
1214
{
15+
private readonly ICursor _cursor;
1316
private readonly IComponentExporter _componentExporter;
1417
private readonly IEventsExporter _eventExporter;
1518
private readonly IStatusSerializer _serializer;
1619

1720
private readonly ILogger<StatusExporter> _logger;
1821

1922
public StatusExporter(
23+
ICursor cursor,
2024
IComponentExporter componentExporter,
2125
IEventsExporter eventExporter,
2226
IStatusSerializer serializer,
2327
ILogger<StatusExporter> logger)
2428
{
29+
_cursor = cursor ?? throw new ArgumentNullException(nameof(cursor));
2530
_componentExporter = componentExporter ?? throw new ArgumentNullException(nameof(componentExporter));
2631
_eventExporter = eventExporter ?? throw new ArgumentNullException(nameof(eventExporter));
2732
_serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
2833
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
2934
}
3035

31-
public Task Export(DateTime cursor)
36+
public async Task Export(DateTime cursor)
3237
{
3338
using (_logger.Scope("Exporting service status."))
3439
{
3540
var rootComponent = _componentExporter.Export();
3641
var recentEvents = _eventExporter.Export(cursor);
37-
return _serializer.Serialize(cursor, rootComponent, recentEvents);
42+
43+
var lastUpdated = await _cursor.Get(StatusUpdater.LastUpdatedCursorName);
44+
await _serializer.Serialize(cursor, lastUpdated, rootComponent, recentEvents);
3845
}
3946
}
4047
}

src/StatusAggregator/Export/StatusSerializer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ public StatusSerializer(
3636
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
3737
}
3838

39-
public async Task Serialize(DateTime cursor, IComponent rootComponent, IEnumerable<Event> recentEvents)
39+
public async Task Serialize(DateTime lastBuilt, DateTime lastUpdated, IComponent rootComponent, IEnumerable<Event> recentEvents)
4040
{
4141
ServiceStatus status;
4242
string statusJson;
4343
using (_logger.Scope("Serializing service status."))
4444
{
45-
status = new ServiceStatus(cursor, rootComponent, recentEvents);
45+
status = new ServiceStatus(lastBuilt, lastUpdated, rootComponent, recentEvents);
4646
statusJson = JsonConvert.SerializeObject(status, Settings);
4747
}
4848

src/StatusAggregator/LogEvents.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ public static class LogEvents
66
{
77
public static EventId RegexFailure = new EventId(400, "Failed to parse incident using Regex.");
88
public static EventId ManualChangeFailure = new EventId(401, "Failed to apply a manual change.");
9+
public static EventId IncidentIngestionFailure = new EventId(402, "Failed to update incident API data.");
910
}
1011
}

src/StatusAggregator/StatusAggregator.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@
160160
<Version>2.33.0</Version>
161161
</PackageReference>
162162
<PackageReference Include="NuGet.Services.Status">
163-
<Version>2.33.0</Version>
163+
<Version>2.37.0-sb-statusfb-2205681</Version>
164164
</PackageReference>
165165
<PackageReference Include="NuGet.Services.Status.Table">
166-
<Version>2.33.0</Version>
166+
<Version>2.37.0-sb-statusfb-2205681</Version>
167167
</PackageReference>
168168
<PackageReference Include="WindowsAzure.Storage">
169169
<Version>9.2.0</Version>

src/StatusAggregator/Update/StatusUpdater.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ namespace StatusAggregator.Update
1313
{
1414
public class StatusUpdater : IStatusUpdater
1515
{
16-
private const string ManualCursorBaseName = "manual";
17-
private const string IncidentCursorName = "incident";
16+
public const string LastUpdatedCursorName = "updated";
1817

1918
private readonly ICursor _cursor;
2019
private readonly IEntityCollector _incidentCollector;
@@ -50,8 +49,17 @@ public async Task Update(DateTime cursor)
5049
await manualStatusChangeCollector.FetchLatest();
5150
}
5251

53-
await _incidentCollector.FetchLatest();
54-
await _activeEventUpdater.UpdateAllAsync(cursor);
52+
try
53+
{
54+
await _incidentCollector.FetchLatest();
55+
await _activeEventUpdater.UpdateAllAsync(cursor);
56+
57+
await _cursor.Set(LastUpdatedCursorName, cursor);
58+
}
59+
catch (Exception e)
60+
{
61+
_logger.LogError(LogEvents.IncidentIngestionFailure, e, "Failed to update incident API data.");
62+
}
5563
}
5664
}
5765

tests/StatusAggregator.Tests/Export/StatusExporterTests.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
using Microsoft.Extensions.Logging;
77
using Moq;
88
using NuGet.Services.Status;
9+
using StatusAggregator.Collector;
910
using StatusAggregator.Export;
11+
using StatusAggregator.Update;
1012
using Xunit;
1113

1214
namespace StatusAggregator.Tests.Export
@@ -29,30 +31,38 @@ public async Task ExportsAtCursor()
2931
EventExporter
3032
.Setup(x => x.Export(cursor))
3133
.Returns(events);
32-
34+
35+
var lastUpdated = new DateTime(2018, 9, 12);
36+
Cursor
37+
.Setup(x => x.Get(StatusUpdater.LastUpdatedCursorName))
38+
.ReturnsAsync(lastUpdated);
39+
3340
await Exporter.Export(cursor);
3441

3542
Serializer
3643
.Verify(
37-
x => x.Serialize(cursor, component, events),
44+
x => x.Serialize(cursor, lastUpdated, component, events),
3845
Times.Once());
3946
}
4047
}
4148

4249
public class StatusExporterTest
4350
{
51+
public Mock<ICursor> Cursor { get; }
4452
public Mock<IComponentExporter> ComponentExporter { get; }
4553
public Mock<IEventsExporter> EventExporter { get; }
4654
public Mock<IStatusSerializer> Serializer { get; }
4755
public StatusExporter Exporter { get; }
4856

4957
public StatusExporterTest()
5058
{
59+
Cursor = new Mock<ICursor>();
5160
ComponentExporter = new Mock<IComponentExporter>();
5261
EventExporter = new Mock<IEventsExporter>();
5362
Serializer = new Mock<IStatusSerializer>();
5463

5564
Exporter = new StatusExporter(
65+
Cursor.Object,
5666
ComponentExporter.Object,
5767
EventExporter.Object,
5868
Serializer.Object,

tests/StatusAggregator.Tests/Export/StatusSerializerTests.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ public class TheSerializeMethod : StatusSerializerTest
2020
[Fact]
2121
public async Task SerializesStatus()
2222
{
23-
var cursor = new DateTime(2018, 9, 13);
23+
var lastBuilt = new DateTime(2018, 11, 13);
24+
var lastUpdated = new DateTime(2018, 9, 13);
2425
var component = new TestComponent("hi", new[] { new TestComponent("yo"), new TestComponent("what's up") });
25-
var events = new[] { new Event("", cursor, cursor, new[] { new Message(cursor, "howdy") }) };
26+
var events = new[] { new Event("", lastUpdated, lastUpdated, new[] { new Message(lastUpdated, "howdy") }) };
2627

27-
var expectedStatus = new ServiceStatus(cursor, component, events);
28+
var expectedStatus = new ServiceStatus(lastBuilt, lastUpdated, component, events);
2829
var expectedJson = JsonConvert.SerializeObject(expectedStatus, StatusSerializer.Settings);
2930

30-
await Serializer.Serialize(cursor, component, events);
31+
await Serializer.Serialize(lastBuilt, lastUpdated, component, events);
3132

3233
Container
3334
.Verify(

tests/StatusAggregator.Tests/StatusAggregator.Tests.csproj

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
<Compile Include="Update\AggregationEntityUpdaterTests.cs" />
9292
<Compile Include="Update\EventMessagingUpdaterTests.cs" />
9393
<Compile Include="Update\IncidentUpdaterTests.cs" />
94+
<Compile Include="Update\StatusUpdaterTests.cs" />
9495
</ItemGroup>
9596
<ItemGroup>
9697
<ProjectReference Include="..\..\src\StatusAggregator\StatusAggregator.csproj">
@@ -111,9 +112,6 @@
111112
<PackageReference Include="System.ValueTuple">
112113
<Version>4.4.0</Version>
113114
</PackageReference>
114-
<PackageReference Include="WindowsAzure.Storage">
115-
<Version>9.2.0</Version>
116-
</PackageReference>
117115
<PackageReference Include="xunit">
118116
<Version>2.4.0</Version>
119117
</PackageReference>

0 commit comments

Comments
 (0)