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