Skip to content

Commit d362a1b

Browse files
hhvrcLucHeart
andauthored
Add ShockerControlLogs Cron clear job (#157)
* Create ClearOldShockerControlLogs.cs * Make job also limit to one million logs * Delete by count per user * Account for a min value of a thousand logs * Fix delete by count per user --------- Co-authored-by: LucHeart <luc@luc.cat>
1 parent f0e7083 commit d362a1b

3 files changed

Lines changed: 73 additions & 0 deletions

File tree

Common/Constants/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
public static class Duration
44
{
55
public static readonly TimeSpan AuditRetentionTime = TimeSpan.FromDays(90);
6+
public static readonly TimeSpan ShockerControlLogRetentionTime = TimeSpan.FromDays(365);
67

78
public static readonly TimeSpan PasswordResetRequestLifetime = TimeSpan.FromHours(1);
89

Common/Constants/HardLimits.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,6 @@ public static class HardLimits
4747
public const int ShockerControlLogCustomNameMaxLength = 64;
4848

4949
public const int CreateShareRequestMaxShockers = 128;
50+
51+
public const int MaxShockerControlLogsPerUser = 2048;
5052
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using OpenShock.Common;
3+
using OpenShock.Common.Constants;
4+
using OpenShock.Common.OpenShockDb;
5+
using OpenShock.Cron.Attributes;
6+
7+
namespace OpenShock.Cron.Jobs;
8+
9+
/// <summary>
10+
/// Deletes shocker control logs older than the retention period and enforces a maximum log count
11+
/// </summary>
12+
[CronJob("0 0 * * *")] // Every day at midnight (https://crontab.guru/)
13+
public sealed class ClearOldShockerControlLogs
14+
{
15+
private readonly OpenShockContext _db;
16+
private readonly ILogger<ClearOldShockerControlLogs> _logger;
17+
18+
/// <summary>
19+
/// DI constructor
20+
/// </summary>
21+
/// <param name="db"></param>
22+
/// <param name="logger"></param>
23+
public ClearOldShockerControlLogs(OpenShockContext db, ILogger<ClearOldShockerControlLogs> logger)
24+
{
25+
_db = db;
26+
_logger = logger;
27+
}
28+
29+
public async Task Execute()
30+
{
31+
// Calculate the retention threshold based on configured retention time.
32+
var retentionThreshold = DateTime.UtcNow - Duration.ShockerControlLogRetentionTime;
33+
34+
// Delete logs older than the retention threshold.
35+
var deletedByAge = await _db.ShockerControlLogs
36+
.Where(log => log.CreatedOn < retentionThreshold)
37+
.ExecuteDeleteAsync();
38+
39+
_logger.LogInformation("Deleted {deletedCount} shocker control logs older than {retentionThreshold:O}.", deletedByAge, retentionThreshold);
40+
41+
var userLogsCounts = await _db.ShockerControlLogs
42+
.GroupBy(log => log.Shocker.DeviceNavigation.Owner)
43+
.Select(group => new
44+
{
45+
UserId = group.Key,
46+
CountToDelete = Math.Max(0, group.Count() - HardLimits.MaxShockerControlLogsPerUser),
47+
DeleteBeforeDate = group
48+
.OrderByDescending(log => log.CreatedOn)
49+
.Skip(HardLimits.MaxShockerControlLogsPerUser)
50+
.Select(log => log.CreatedOn)
51+
.FirstOrDefault()
52+
})
53+
.Where(result => result.CountToDelete > 0)
54+
.ToArrayAsync();
55+
56+
if (userLogsCounts.Length != 0)
57+
{
58+
_logger.LogInformation("A total of {totalLogsToDelete} logs will be deleted to enforce per-user limits.", userLogsCounts.Sum(x => x.CountToDelete));
59+
60+
foreach (var userLogCount in userLogsCounts)
61+
{
62+
await _db.ShockerControlLogs
63+
.Where(log => log.Shocker.DeviceNavigation.Owner == userLogCount.UserId && log.CreatedOn < userLogCount.DeleteBeforeDate)
64+
.ExecuteDeleteAsync();
65+
}
66+
}
67+
68+
_logger.LogInformation("Done!");
69+
}
70+
}

0 commit comments

Comments
 (0)