Skip to content

Commit b7e774b

Browse files
committed
Activated the background jobs
1 parent 329d5a1 commit b7e774b

File tree

22 files changed

+346
-42
lines changed

22 files changed

+346
-42
lines changed

src/Server/Coderr.Server.Abstractions/Boot/ContainerServiceAttribute.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ public class ContainerServiceAttribute: Attribute
66
{
77
public bool IsSingleInstance { get; set; }
88
public bool IsTransient { get; set; }
9+
public bool RegisterAsSelf { get; set; }
910
}
1011
}

src/Server/Coderr.Server.Abstractions/Boot/RegisterExtensions.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,21 @@ public static void RegisterContainerServices(this IServiceCollection serviceColl
1818
var interfaces = containerService.GetInterfaces();
1919

2020
// Hack so that the same instance is resolved for each interface
21-
if (interfaces.Length > 1)
21+
if (interfaces.Length > 1 || attr.RegisterAsSelf)
2222
serviceCollection.RegisterService(attr, containerService, containerService);
2323

2424
foreach (var @interface in interfaces)
2525
{
2626
serviceCollection.RegisterService(attr, @interface, containerService);
2727
}
28-
2928
}
3029
}
3130

32-
private static void RegisterService(this IServiceCollection serviceCollection, ContainerServiceAttribute attr,
33-
Type service, Type implementation)
34-
{
35-
if (attr.IsSingleInstance)
36-
serviceCollection.AddSingleton(service, implementation);
37-
else if (attr.IsTransient)
38-
serviceCollection.AddTransient(service, implementation);
39-
else
40-
serviceCollection.AddScoped(service, implementation);
41-
}
42-
4331
public static void RegisterMessageHandlers(this IServiceCollection serviceCollection, Assembly assembly)
4432
{
4533
var types = assembly.GetTypes()
46-
.Where(y => y.GetInterfaces().Any(x => x.Name.Contains("IMessageHandler") || x.Name.Contains("IQueryHandler")))
34+
.Where(y => y.GetInterfaces()
35+
.Any(x => x.Name.Contains("IMessageHandler") || x.Name.Contains("IQueryHandler")))
4736
.ToList();
4837
foreach (var type in types)
4938
{
@@ -52,5 +41,15 @@ public static void RegisterMessageHandlers(this IServiceCollection serviceCollec
5241
}
5342
}
5443

44+
private static void RegisterService(this IServiceCollection serviceCollection, ContainerServiceAttribute attr,
45+
Type service, Type implementation)
46+
{
47+
if (attr.IsSingleInstance)
48+
serviceCollection.AddSingleton(service, implementation);
49+
else if (attr.IsTransient)
50+
serviceCollection.AddTransient(service, implementation);
51+
else
52+
serviceCollection.AddScoped(service, implementation);
53+
}
5554
}
56-
}
55+
}

src/Server/Coderr.Server.Abstractions/Config/IConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
public interface IConfiguration<out TConfigType> where TConfigType : new()
44
{
55
TConfigType Value { get; }
6+
7+
void Save();
68
}
79
}

src/Server/Coderr.Server.App/Core/Incidents/Jobs/DeleteEmptyIncidents.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace Coderr.Server.App.Core.Incidents.Jobs
1919
/// when there are no reports for them. Do note that ignored incidents will not be deleted.
2020
/// </para>
2121
/// </remarks>
22-
[ContainerService]
22+
[ContainerService(RegisterAsSelf = true)]
2323
internal class DeleteEmptyIncidents : IBackgroundJobAsync
2424
{
2525
private readonly ILog _logger = LogManager.GetLogger(typeof(DeleteEmptyIncidents));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Coderr.Server.App.Core.Reports.Jobs
1313
/// Will delete all reports which is older than the configured (<see cref="ReportConfig.RetentionDays" />) retention
1414
/// period.
1515
/// </summary>
16-
[ContainerService]
16+
[ContainerService(RegisterAsSelf = true)]
1717
public class DeleteOldReports : IBackgroundJobAsync
1818
{
1919
private readonly ILog _logger = LogManager.GetLogger(typeof(DeleteOldReports));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace Coderr.Server.App.Core.Reports.Jobs
1818
/// You can configure the amount of reports per incident in the admin area.
1919
/// </para>
2020
/// </remarks>
21-
[ContainerService]
21+
[ContainerService(RegisterAsSelf = true)]
2222
public class DeleteReportsBelowReportLimit : IBackgroundJob
2323
{
2424
private readonly ILog _logger = LogManager.GetLogger(typeof(DeleteReportsBelowReportLimit));

src/Server/Coderr.Server.App/Core/Support/SendSupportRequestHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public SendSupportRequestHandler(ConfigurationStore configStore)
3434
public async Task HandleAsync(IMessageContext context, SendSupportRequest command)
3535
{
3636
var baseConfig = _configStore.Load<BaseConfiguration>();
37-
var errorConfig = _configStore.Load<codeRRConfigSection>();
37+
var errorConfig = _configStore.Load<CoderrConfigSection>();
3838

3939
string email = null;
4040
var claim = context.Principal.FindFirst(ClaimTypes.Email);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Coderr.Server.App.Modules.MonthlyStats
2+
{
3+
public class AppResult
4+
{
5+
public int ApplicationId { get; set; }
6+
public int Count { get; set; }
7+
}
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Coderr.Server.App.Modules.MonthlyStats
2+
{
3+
public class ApplicationUsageStatisticsDto
4+
{
5+
public int ApplicationId { get; set; }
6+
public int ReportCount { get; set; }
7+
public int IncidentCount { get; set; }
8+
}
9+
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net.Http;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Coderr.Server.Abstractions.Boot;
8+
using Coderr.Server.Abstractions.Config;
9+
using Coderr.Server.Infrastructure.Configuration;
10+
using Griffin.ApplicationServices;
11+
using Griffin.Data;
12+
using Newtonsoft.Json;
13+
14+
namespace Coderr.Server.App.Modules.MonthlyStats
15+
{
16+
[ContainerService(RegisterAsSelf = true)]
17+
internal class CollectStatsJob : IBackgroundJobAsync
18+
{
19+
private readonly IConfiguration<CoderrConfigSection> _reportConfiguration;
20+
private readonly IConfiguration<UsageStatsSettings> _config;
21+
private readonly IAdoNetUnitOfWork _unitOfWork;
22+
private static DateTime _reportDate = DateTime.MinValue;
23+
24+
public CollectStatsJob(IAdoNetUnitOfWork unitOfWork, IConfiguration<UsageStatsSettings> config,
25+
IConfiguration<CoderrConfigSection> reportConfiguration)
26+
{
27+
_unitOfWork = unitOfWork;
28+
_config = config;
29+
_reportConfiguration = reportConfiguration;
30+
}
31+
32+
public async Task ExecuteAsync()
33+
{
34+
var lastMonthDate = DateTime.Today.AddMonths(-1);
35+
if (_reportDate == lastMonthDate)
36+
return;
37+
38+
var lastMonth = new DateTime(lastMonthDate.Year, lastMonthDate.Month, 1);
39+
if (_config.Value.LatestUploadedMonth == null)
40+
{
41+
await ReportAllFoundMonths(lastMonth);
42+
return;
43+
}
44+
45+
if (_config.Value?.LatestUploadedMonth == lastMonth)
46+
return;
47+
48+
49+
await ReportMonth(lastMonth);
50+
}
51+
52+
private async Task<AppResult[]> GetIncidentCounts(DateTime lastMonth)
53+
{
54+
var results = new List<AppResult>();
55+
using (var cmd = _unitOfWork.CreateDbCommand())
56+
{
57+
cmd.CommandText = @"select Incidents.ApplicationId, count(incidents.Id)
58+
from incidents
59+
where Incidents.CreatedAtUtc >= @fromDate AND Incidents.CreatedAtUtc < @toDate
60+
group by Incidents.ApplicationId";
61+
cmd.AddParameter("fromDate", lastMonth);
62+
cmd.AddParameter("toDate", lastMonth.AddMonths(1));
63+
using (var reader = await cmd.ExecuteReaderAsync())
64+
{
65+
while (await reader.ReadAsync())
66+
{
67+
var item = new AppResult
68+
{
69+
ApplicationId = reader.GetInt32(0),
70+
Count = reader.GetInt32(1)
71+
};
72+
results.Add(item);
73+
}
74+
}
75+
}
76+
77+
return results.ToArray();
78+
}
79+
80+
private async Task<AppResult[]> GetReportCounts(DateTime lastMonth)
81+
{
82+
var results = new List<AppResult>();
83+
using (var cmd = _unitOfWork.CreateDbCommand())
84+
{
85+
cmd.CommandText = @"select ApplicationId, count(*)
86+
from ErrorReports
87+
where CreatedAtUtc >= @fromDate AND CreatedAtUtc < @toDate
88+
group by ApplicationId";
89+
cmd.AddParameter("fromDate", lastMonth);
90+
cmd.AddParameter("toDate", lastMonth.AddMonths(1));
91+
using (var reader = await cmd.ExecuteReaderAsync())
92+
{
93+
while (await reader.ReadAsync())
94+
{
95+
var item = new AppResult
96+
{
97+
ApplicationId = reader.GetInt32(0),
98+
Count = reader.GetInt32(1)
99+
};
100+
results.Add(item);
101+
}
102+
}
103+
}
104+
105+
return results.ToArray();
106+
}
107+
108+
private async Task ReportAllFoundMonths(DateTime lastMonth)
109+
{
110+
while (true)
111+
{
112+
var result = await ReportMonth(lastMonth);
113+
if (!result)
114+
break;
115+
116+
lastMonth = lastMonth.AddMonths(-1);
117+
}
118+
}
119+
120+
private async Task<bool> ReportMonth(DateTime lastMonth)
121+
{
122+
var apps = new Dictionary<int, ApplicationUsageStatisticsDto>();
123+
124+
var incidentCounts = await GetIncidentCounts(lastMonth);
125+
foreach (var count in incidentCounts)
126+
{
127+
if (count.Count == 0)
128+
continue;
129+
if (!apps.TryGetValue(count.ApplicationId, out var value))
130+
{
131+
value = new ApplicationUsageStatisticsDto
132+
{
133+
ApplicationId = count.ApplicationId
134+
};
135+
apps[value.ApplicationId] = value;
136+
}
137+
138+
value.IncidentCount = count.Count;
139+
}
140+
141+
var reportCounts = await GetReportCounts(lastMonth);
142+
foreach (var count in reportCounts)
143+
{
144+
if (count.Count == 0)
145+
continue;
146+
if (!apps.TryGetValue(count.ApplicationId, out var value))
147+
{
148+
value = new ApplicationUsageStatisticsDto
149+
{
150+
ApplicationId = count.ApplicationId
151+
};
152+
apps[value.ApplicationId] = value;
153+
}
154+
155+
value.ReportCount = count.Count;
156+
}
157+
158+
if (_config.Value.LatestUploadedMonth == null || _config.Value.LatestUploadedMonth < lastMonth)
159+
{
160+
_config.Value.LatestUploadedMonth = lastMonth;
161+
_reportDate = lastMonth;
162+
_config.Save();
163+
}
164+
165+
if (apps.Count == 0)
166+
return false;
167+
168+
var dto = new UsageStatisticsDto
169+
{
170+
InstallationId = _reportConfiguration.Value.InstallationId,
171+
Applications = apps.Values.ToArray(),
172+
YearMonth = lastMonth
173+
};
174+
var json = JsonConvert.SerializeObject(dto);
175+
var client = new HttpClient();
176+
var content = new StringContent(json, Encoding.UTF8, "application/json");
177+
await client.PostAsync("http://localhost:54782/stats/usage", content);
178+
return true;
179+
}
180+
}
181+
}

0 commit comments

Comments
 (0)