Skip to content

Commit 55b54e7

Browse files
authored
Discard fixed stack events that don't regress #1507
Discard fixed stack events that don't regress
2 parents 03cb110 + 247a0fe commit 55b54e7

File tree

2 files changed

+99
-7
lines changed

2 files changed

+99
-7
lines changed

src/Exceptionless.Core/Pipeline/030_CheckForRegressionAction.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public CheckForRegressionAction(IStackRepository stackRepository, SemanticVersio
2323
public override async Task ProcessBatchAsync(ICollection<EventContext> contexts)
2424
{
2525
var stacks = contexts
26-
.Where(c => c.Stack is not null && c.Stack.Status != StackStatus.Regressed && c.Stack.DateFixed.HasValue)
26+
.Where(c => c.Stack is { Status: StackStatus.Fixed, DateFixed: not null })
2727
.OrderBy(c => c.Event.Date)
2828
.GroupBy(c => c.Event.StackId);
2929

@@ -52,7 +52,16 @@ public override async Task ProcessBatchAsync(ICollection<EventContext> contexts)
5252
{
5353
var version = _semanticVersionParser.Parse(versionGroup.Key, versionCache) ?? _semanticVersionParser.Default;
5454
if (version < fixedInVersion)
55+
{
56+
foreach (var ctx in stackGroup.Where(s => s.Organization.HasPremiumFeatures))
57+
{
58+
_logger.LogDebug("Discarding fixed stack event: Version {Version} is older than fixed in version {FixedInVersion}", version, fixedInVersion);
59+
ctx.IsDiscarded = true;
60+
ctx.IsCancelled = true;
61+
}
62+
5563
continue;
64+
}
5665

5766
regressedVersion = version;
5867
regressedContext = versionGroup.First();
@@ -63,7 +72,7 @@ public override async Task ProcessBatchAsync(ICollection<EventContext> contexts)
6372
if (regressedContext is null)
6473
return;
6574

66-
_logger.LogTrace("Marking stack and events as regressed in version: {Version}", regressedVersion);
75+
_logger.LogDebug("Marking stack and events as regressed in version: {Version}", regressedVersion);
6776
stack.Status = StackStatus.Regressed;
6877
await _stackRepository.MarkAsRegressedAsync(stack.Id);
6978

@@ -79,7 +88,10 @@ public override async Task ProcessBatchAsync(ICollection<EventContext> contexts)
7988
{
8089
cont = HandleError(ex, context);
8190
}
82-
catch { }
91+
catch (Exception hex)
92+
{
93+
_logger.LogError(hex, "Error calling HandleError: {Message}", ex.Message);
94+
}
8395

8496
if (!cont)
8597
context.SetError(ex.Message, ex);

tests/Exceptionless.Tests/Pipeline/EventPipelineTests.cs

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Exceptionless.Core.Queues.Models;
1313
using Exceptionless.Core.Repositories;
1414
using Exceptionless.Core.Repositories.Configuration;
15+
using Exceptionless.Core.Utility;
1516
using Exceptionless.DateTimeExtensions;
1617
using Exceptionless.Tests.Utility;
1718
using Foundatio.Repositories;
@@ -929,7 +930,7 @@ public async Task WillHandleDiscardedStack()
929930
var organization = OrganizationData.GenerateSampleOrganization(_billingManager, _plans);
930931
var project = ProjectData.GenerateSampleProject();
931932

932-
var ev = EventData.GenerateEvent(organizationId: TestConstants.OrganizationId, projectId: TestConstants.ProjectId, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow);
933+
var ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow);
933934
var context = await _pipeline.RunAsync(ev, organization, project);
934935
Assert.True(context.IsProcessed);
935936
Assert.False(context.HasError);
@@ -944,22 +945,101 @@ public async Task WillHandleDiscardedStack()
944945
stack.Status = StackStatus.Discarded;
945946
stack = await _stackRepository.SaveAsync(stack, o => o.ImmediateConsistency());
946947

947-
948-
ev = EventData.GenerateEvent(organizationId: TestConstants.OrganizationId, projectId: TestConstants.ProjectId, stackId: ev.StackId, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow);
948+
ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow);
949949
context = await _pipeline.RunAsync(ev, organization, project);
950950
Assert.False(context.IsProcessed);
951951
Assert.False(context.HasError);
952952
Assert.True(context.IsCancelled);
953953
Assert.True(context.IsDiscarded);
954954
await RefreshDataAsync();
955955

956-
ev = EventData.GenerateEvent(organizationId: TestConstants.OrganizationId, projectId: TestConstants.ProjectId, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow);
956+
ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow);
957957
context = await _pipeline.RunAsync(ev, organization, project);
958958
Assert.False(context.IsProcessed);
959959
Assert.False(context.HasError);
960960
Assert.True(context.IsCancelled);
961961
Assert.True(context.IsDiscarded);
962+
}
963+
964+
[Theory]
965+
[InlineData(StackStatus.Regressed, false, null, null)]
966+
[InlineData(StackStatus.Fixed, true, "1.0.0", null)] // A fixed stack should not be marked as regressed if the event has no version.
967+
[InlineData(StackStatus.Regressed, false, null, "1.0.0")]
968+
[InlineData(StackStatus.Regressed, false, "1.0.0", "1.0.0")] // A fixed stack should not be marked as regressed if the event has the same version.
969+
[InlineData(StackStatus.Fixed, true, "2.0.0", "1.0.0")]
970+
[InlineData(StackStatus.Regressed, false, null, "1.0.1")]
971+
[InlineData(StackStatus.Regressed, false, "1.0.0", "1.0.1")]
972+
public async Task CanDiscardStackEventsBasedOnEventVersion(StackStatus expectedStatus, bool expectedDiscard, string? stackFixedInVersion, string? eventSemanticVersion)
973+
{
974+
var organization = await _organizationRepository.GetByIdAsync(TestConstants.OrganizationId, o => o.Cache());
975+
var project = await _projectRepository.GetByIdAsync(TestConstants.ProjectId, o => o.Cache());
976+
977+
var ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow);
978+
var context = await _pipeline.RunAsync(ev, organization, project);
979+
980+
var stack = context.Stack;
981+
Assert.NotNull(stack);
982+
Assert.Equal(StackStatus.Open, stack.Status);
983+
984+
Assert.True(context.IsProcessed);
985+
Assert.False(context.HasError);
986+
Assert.False(context.IsCancelled);
987+
Assert.False(context.IsDiscarded);
988+
989+
var semanticVersionParser = GetService<SemanticVersionParser>();
990+
var fixedInVersion = semanticVersionParser.Parse(stackFixedInVersion);
991+
stack.MarkFixed(fixedInVersion);
992+
await _stackRepository.SaveAsync(stack, o => o.ImmediateConsistency());
993+
994+
await RefreshDataAsync();
995+
ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow, semver: eventSemanticVersion);
996+
context = await _pipeline.RunAsync(ev, organization, project);
997+
998+
stack = context.Stack;
999+
Assert.NotNull(stack);
1000+
Assert.Equal(expectedStatus, stack.Status);
1001+
Assert.Equal(expectedDiscard, context.IsCancelled);
1002+
Assert.Equal(expectedDiscard, context.IsDiscarded);
1003+
}
1004+
1005+
[Theory]
1006+
[InlineData("1.0.0", null)] // A fixed stack should not be marked as regressed if the event has no version.
1007+
[InlineData("2.0.0", "1.0.0")]
1008+
public async Task WillNotDiscardStackEventsBasedOnEventVersionWithFreePlan(string stackFixedInVersion, string? eventSemanticVersion)
1009+
{
1010+
var organization = await _organizationRepository.GetByIdAsync(TestConstants.OrganizationId3, o => o.Cache());
1011+
1012+
var plans = GetService<BillingPlans>();
1013+
Assert.Equal(plans.FreePlan.Id, organization.PlanId);
1014+
1015+
var project = await _projectRepository.AddAsync(ProjectData.GenerateProject(organizationId: organization.Id), o => o.ImmediateConsistency().Cache());
1016+
1017+
var ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow);
1018+
var context = await _pipeline.RunAsync(ev, organization, project);
1019+
1020+
var stack = context.Stack;
1021+
Assert.NotNull(stack);
1022+
Assert.Equal(StackStatus.Open, stack.Status);
1023+
1024+
Assert.True(context.IsProcessed);
1025+
Assert.False(context.HasError);
1026+
Assert.False(context.IsCancelled);
1027+
Assert.False(context.IsDiscarded);
1028+
1029+
var semanticVersionParser = GetService<SemanticVersionParser>();
1030+
var fixedInVersion = semanticVersionParser.Parse(stackFixedInVersion);
1031+
stack.MarkFixed(fixedInVersion);
1032+
await _stackRepository.SaveAsync(stack, o => o.ImmediateConsistency());
1033+
9621034
await RefreshDataAsync();
1035+
ev = EventData.GenerateEvent(organizationId: organization.Id, projectId: project.Id, type: Event.KnownTypes.Log, source: "test", occurrenceDate: SystemClock.OffsetNow, semver: eventSemanticVersion);
1036+
context = await _pipeline.RunAsync(ev, organization, project);
1037+
1038+
stack = context.Stack;
1039+
Assert.NotNull(stack);
1040+
Assert.Equal(StackStatus.Fixed, stack.Status);
1041+
Assert.False(context.IsCancelled);
1042+
Assert.False(context.IsDiscarded);
9631043
}
9641044

9651045
[Theory]

0 commit comments

Comments
 (0)