Skip to content

Commit 54e1ed8

Browse files
committed
Corrected issues in the SQL schema updater, improved performance of the backround job that deletes old reports.
1 parent afaff69 commit 54e1ed8

File tree

22 files changed

+92
-100
lines changed

22 files changed

+92
-100
lines changed

src/Server/Coderr.Server.Api.Client.Tests/codeRR.Server.Api.Client.Tests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
</PropertyGroup>
77
<ItemGroup>
88
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
9-
<PackageReference Include="xunit" Version="2.2.0" />
10-
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
9+
<PackageReference Include="xunit" Version="2.3.1" />
10+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
1111
<PackageReference Include="FluentAssertions" Version="4.19.4" />
1212
<PackageReference Include="NSubstitute" Version="2.0.3" />
1313

src/Server/Coderr.Server.App.Tests/codeRR.Server.App.Tests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
</PropertyGroup>
77
<ItemGroup>
88
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
9-
<PackageReference Include="xunit" Version="2.2.0" />
10-
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
9+
<PackageReference Include="xunit" Version="2.3.1" />
10+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
1111
<PackageReference Include="FluentAssertions" Version="4.19.4" />
1212
<PackageReference Include="NSubstitute" Version="2.0.3" />
1313

src/Server/Coderr.Server.App/Core/Notifications/Tasks/SendIncidentEmail.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task SendAsync(IMessageContext context, string idOrEmailAddress, In
4545
// need to be safe for subjects
4646
shortName = shortName.Replace("\n", ";");
4747

48-
var baseUrl = string.Format("{0}/#/application/{1}/incident/{2}",
48+
var baseUrl = string.Format("{0}/#/application/{1}/incident/{2}/",
4949
config.BaseUrl.ToString().TrimEnd('/'),
5050
report.ApplicationId,
5151
report.IncidentId);
@@ -56,7 +56,7 @@ public async Task SendAsync(IMessageContext context, string idOrEmailAddress, In
5656
{
5757
msg.Subject = "ReOpened: " + shortName;
5858
msg.TextBody = string.Format(@"Incident: {0}
59-
Report url: {0}/report/{1}
59+
Report url: {0}/report/{1}/
6060
Description: {2}
6161
Exception: {3}
6262
@@ -76,7 +76,7 @@ public async Task SendAsync(IMessageContext context, string idOrEmailAddress, In
7676
{
7777
msg.Subject = "Updated: " + shortName;
7878
msg.TextBody = string.Format(@"Incident: {0}
79-
Report url: {0}/report/{1}
79+
Report url: {0}/report/{1}/
8080
Description: {2}
8181
Exception: {3}
8282

src/Server/Coderr.Server.App/Core/Reports/Jobs/DeleteReportsBelowReportLimit.cs

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public int MaxReportsPerIncident
4444
{
4545
var config = _configStore.Load<ReportConfig>();
4646
if (config == null)
47-
return 5000;
47+
return 1;
4848
return config.MaxReportsPerIncident;
4949
}
5050
}
@@ -53,48 +53,46 @@ public int MaxReportsPerIncident
5353
public void Execute()
5454
{
5555
// find incidents with too many reports.
56-
var incidentsToTruncate = new List<int>();
56+
var incidentsToTruncate = new List<Tuple<int, int>>();
5757
using (var cmd = _unitOfWork.CreateCommand())
5858
{
5959
cmd.CommandText =
60-
@"SELECT TOP 10 Id FROM Incidents WHERE ReportCount > @max ORDER BY ReportCount DESC";
60+
@"SELECT TOP(5) IncidentId, count(Id)
61+
FROM ErrorReports
62+
GROUP BY IncidentId
63+
HAVING Count(IncidentId) > @max
64+
ORDER BY count(Id) DESC";
6165
cmd.AddParameter("max", MaxReportsPerIncident);
6266
using (var reader = cmd.ExecuteReader())
6367
{
6468
while (reader.Read())
6569
{
66-
incidentsToTruncate.Add((int) reader[0]);
70+
incidentsToTruncate.Add(new Tuple<int, int>((int)reader[0], (int)reader[1]));
6771
}
6872
}
6973
}
7074

71-
foreach (var incidentId in incidentsToTruncate)
75+
foreach (var incidentIdAndCount in incidentsToTruncate)
7276
{
77+
var rowsToDelete = Math.Min(1000, incidentIdAndCount.Item2 - MaxReportsPerIncident);
7378
using (var cmd = _unitOfWork.CreateCommand())
7479
{
75-
var sql = @"DELETE FROM ErrorReports WHERE IncidentId = @id AND Id <= (SELECT Id
76-
FROM ErrorReports
77-
WHERE IncidentId = @id
78-
ORDER BY Id DESC
79-
OFFSET {0} ROWS
80-
FETCH NEXT 1 ROW ONLY)";
81-
cmd.CommandText = string.Format(sql, MaxReportsPerIncident);
82-
cmd.AddParameter("id", incidentId);
80+
var sql = $@"With RowsToDelete AS
81+
(
82+
SELECT TOP {rowsToDelete} Id
83+
FROM ErrorReports
84+
WHERE IncidentId = {incidentIdAndCount.Item1}
85+
ORDER BY ID ASC
86+
)
87+
DELETE FROM RowsToDelete";
88+
cmd.CommandText = sql;
8389
cmd.CommandTimeout = 90;
8490
var rows = cmd.ExecuteNonQuery();
8591
if (rows > 0)
8692
{
87-
_logger.Debug("Deleted the oldest " + rows + " reports for incident " + incidentId);
93+
_logger.Debug("Deleted the oldest " + rows + " reports for incident " + incidentIdAndCount);
8894
}
8995
}
90-
91-
using (var cmd = _unitOfWork.CreateCommand())
92-
{
93-
cmd.CommandText =
94-
@"UPDATE Incidents SET ReportCount = (SELECT count(Id) FROM ErrorReports WHERE IncidentId = @id) WHERE Id = @id";
95-
cmd.AddParameter("id", incidentId);
96-
cmd.ExecuteNonQuery();
97-
}
9896
}
9997
}
10098
}

src/Server/Coderr.Server.Infrastructure/codeRR.Server.Infrastructure.csproj

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
<AssemblyName>Coderr.Server.Infrastructure</AssemblyName>
66
</PropertyGroup>
77
<ItemGroup>
8-
<PackageReference Include="Griffin.Container" Version="1.1.7" />
9-
<PackageReference Include="Griffin.Framework" Version="2.0.0-alpha01" />
10-
<PackageReference Include="log4net" Version="2.0.8" />
11-
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
8+
<PackageReference Include="DotNetCqs" Version="2.0.3.8" />
9+
<PackageReference Include="Griffin.Container" Version="1.1.7" />
10+
<PackageReference Include="Griffin.Framework" Version="2.0.0-alpha01" />
11+
<PackageReference Include="log4net" Version="2.0.8" />
12+
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
1213
</ItemGroup>
1314
<ItemGroup>
1415
<ProjectReference Include="..\Coderr.Server.Api\codeRR.Server.Api.csproj" />

src/Server/Coderr.Server.ReportAnalyzer.Tests/codeRR.Server.ReportAnalyzer.Tests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
</PropertyGroup>
77
<ItemGroup>
88
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
9-
<PackageReference Include="xunit" Version="2.2.0" />
10-
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
9+
<PackageReference Include="xunit" Version="2.3.1" />
10+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
1111
<PackageReference Include="FluentAssertions" Version="4.19.4" />
1212
<PackageReference Include="NSubstitute" Version="2.0.3" />
1313
</ItemGroup>

src/Server/Coderr.Server.SqlServer.Tests/TestTools.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,22 @@ public class TestTools : IDisposable
2424
public TestTools()
2525
{
2626
ConfigStore = new TestConfigStore();
27+
CanDropDatabase = true;
2728
}
2829

2930
public ConfigurationStore ConfigStore { get; private set; }
3031

32+
public bool CanDropDatabase { get; set; }
3133

3234
public void Dispose()
3335
{
3436
if (_dbName == null)
3537
return;
38+
if (!CanDropDatabase)
39+
{
40+
Console.WriteLine("Do not delete " + _dbName);
41+
return;
42+
}
3643

3744
using (var con = ConnectionFactory.OpenConnection())
3845
{
@@ -51,7 +58,7 @@ public void CreateBasicData()
5158

5259
var report = new ErrorReportEntity(applicationId, Guid.NewGuid().ToString("N"), DateTime.UtcNow,
5360
new ErrorReportException(new Exception("mofo")),
54-
new List<ErrorReportContext> {new ErrorReportContext("Maps", new Dictionary<string, string>())});
61+
new List<ErrorReportContext> { new ErrorReportContext("Maps", new Dictionary<string, string>()) });
5562
report.Title = "Missing here";
5663
report.Init(report.GenerateHashCodeIdentifier());
5764

@@ -69,7 +76,7 @@ public void CreateDatabase()
6976
{
7077
using (var con = ConnectionFactory.OpenConnection())
7178
{
72-
_dbName = "T" + Guid.NewGuid().ToString("N");
79+
_dbName = "CdrTest" + Guid.NewGuid().ToString("N").Substring(0, 8);
7380
con.ExecuteNonQuery("CREATE Database " + _dbName);
7481
con.ChangeDatabase(_dbName);
7582
var schemaTool = new SchemaManager(() => con);
@@ -107,10 +114,10 @@ public void ToLatestVersion()
107114
protected void CreateUserAndApplication(IAdoNetUnitOfWork uow, out int accountId, out int applicationId)
108115
{
109116
var accountRepos = new AccountRepository(uow);
110-
var account = new Account("arne", "123456") {Email = "arne@som.com"};
117+
var account = new Account("arne", "123456") { Email = "arne@som.com" };
111118
accountRepos.Create(account);
112119
var userRepos = new UserRepository(uow);
113-
var user = new User(account.Id, "arne") {EmailAddress = "arne@som.com"};
120+
var user = new User(account.Id, "arne") { EmailAddress = "arne@som.com" };
114121
userRepos.CreateAsync(user).GetAwaiter().GetResult();
115122

116123
var appRepos = new ApplicationRepository(uow);

src/Server/Coderr.Server.SqlServer.Tests/codeRR.Server.SqlServer.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<PackageReference Include="xunit" Version="2.3.1" />
1010
<PackageReference Include="FluentAssertions" Version="4.19.4" />
1111
<PackageReference Include="NSubstitute" Version="3.1.0" />
12+
<PackageReference Include="DotNetCqs" Version="2.0.3.8" />
1213
</ItemGroup>
1314
<ItemGroup>
1415
<ProjectReference Include="..\Coderr.Server.SqlServer\codeRR.Server.SqlServer.csproj" />

src/Server/Coderr.Server.SqlServer/Schema/Update.v8.sql

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,33 @@ ALTER TABLE Incidents ADD AssignedAtUtc datetime;
44
ALTER TABLE Incidents ADD LastReportAtUtc datetime;
55

66
DECLARE @ConstraintName nvarchar(200)
7-
SELECT @ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS
8-
WHERE PARENT_OBJECT_ID = OBJECT_ID('incidents')
9-
AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns
10-
WHERE NAME = N'IsSolved'
11-
AND object_id = OBJECT_ID(N'Incidents'))
12-
IF @ConstraintName IS NOT NULL
13-
EXEC('ALTER TABLE incidents DROP CONSTRAINT ' + @ConstraintName)
14-
alter table incidents drop column IsSolved;
7+
SELECT @ConstraintName = d.Name
8+
FROM SYS.DEFAULT_CONSTRAINTS d, sys.columns c
9+
WHERE c.name = 'IsSolved'
10+
AND c.object_id = OBJECT_ID(N'Incidents')
11+
AND d.PARENT_COLUMN_ID = c.column_id
12+
EXEC('ALTER TABLE Incidents DROP CONSTRAINT ' + @ConstraintName)
13+
alter table Incidents drop column IsSolved;
1514

16-
SELECT @ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS
17-
WHERE PARENT_OBJECT_ID = OBJECT_ID('incidents')
18-
AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns
19-
WHERE NAME = N'IgnoreReports'
20-
AND object_id = OBJECT_ID(N'Incidents'))
21-
IF @ConstraintName IS NOT NULL
22-
EXEC('ALTER TABLE incidents DROP CONSTRAINT ' + @ConstraintName)
23-
alter table incidents drop column IgnoreReports;
15+
SELECT @ConstraintName = d.Name
16+
FROM SYS.DEFAULT_CONSTRAINTS d, sys.columns c
17+
WHERE c.name = 'IgnoreReports'
18+
AND c.object_id = OBJECT_ID(N'Incidents')
19+
AND d.PARENT_COLUMN_ID = c.column_id
20+
EXEC('ALTER TABLE Incidents DROP CONSTRAINT ' + @ConstraintName)
21+
alter table Incidents drop column IgnoreReports;
2422

2523
-- ApiKey module deletes relations manually.
26-
DECLARE @ConstraintName nvarchar(200)
27-
SELECT @ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS
28-
WHERE PARENT_OBJECT_ID = OBJECT_ID('incidents')
29-
AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns
30-
WHERE NAME = N'ApplicationId'
31-
AND object_id = OBJECT_ID(N'ApiKeyApplications'))
32-
IF @ConstraintName IS NOT NULL
33-
EXEC('ALTER TABLE ApiKeyApplications DROP CONSTRAINT ' + @ConstraintName)
34-
24+
SELECT
25+
@ConstraintName = KCU.CONSTRAINT_NAME
26+
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
27+
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
28+
ON KCU.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
29+
AND KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
30+
AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
31+
WHERE
32+
KCU.TABLE_NAME = 'ApiKeyApplications' AND
33+
KCU.COLUMN_NAME = 'ApplicationId'
34+
IF @ConstraintName IS NOT NULL EXEC('alter table ApiKeyApplications drop CONSTRAINT ' + @ConstraintName)
3535

3636
UPDATE DatabaseSchema SET Version = 8;

src/Server/Coderr.Server.Web/App_Start/Services/ServiceRunner.cs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ private void BuildServices()
126126
_backgroundJobManager = new BackgroundJobManager(CompositionRoot.Container);
127127
_backgroundJobManager.JobFailed += OnJobFailed;
128128
_backgroundJobManager.StartInterval = TimeSpan.FromSeconds(Debugger.IsAttached ? 0 : 10);
129-
_backgroundJobManager.ExecuteInterval = TimeSpan.FromMinutes(5);
129+
_backgroundJobManager.ExecuteInterval = TimeSpan.FromMinutes(3);
130130

131131
_backgroundJobManager.ScopeClosing += OnBackgroundJobScopeClosing;
132132
}
@@ -147,27 +147,20 @@ private IMessageInvoker CreateMessageInvoker(IServiceLocator x)
147147
Err.Report(ex, new {args.Message});
148148
}
149149
};
150-
invoker.InvokingHandler += (sender, args) =>
151-
{
152-
_log.Debug($"Invoking {args.Handler} in scope " + scope.GetHashCode());
153-
};
154150
invoker.HandlerInvoked += (sender, args) =>
155151
{
156152
if (args.Exception == null)
157-
_log.Debug($"Ran {args.Handler}, took {args.ExecutionTime.TotalMilliseconds}ms");
158-
else
159-
{
160-
Err.Report(args.Exception, new
161-
{
162-
args.Message,
163-
HandlerType = args.Handler.GetType(),
164-
args.ExecutionTime
165-
});
166-
_log.Error(
167-
$"Ran {args.Handler}, took {args.ExecutionTime.TotalMilliseconds}ms, but FAILED.",
168-
args.Exception);
153+
return;
169154

170-
}
155+
Err.Report(args.Exception, new
156+
{
157+
args.Message,
158+
HandlerType = args.Handler.GetType(),
159+
args.ExecutionTime
160+
});
161+
_log.Error(
162+
$"Ran {args.Handler}, took {args.ExecutionTime.TotalMilliseconds}ms, but FAILED.",
163+
args.Exception);
171164
};
172165
return invoker;
173166
}

0 commit comments

Comments
 (0)