Skip to content

Commit 2e192dd

Browse files
committed
feat: add scheduled conversation log cleanup via crontab hook
1 parent 3dc3ee8 commit 2e192dd

4 files changed

Lines changed: 108 additions & 104 deletions

File tree

src/Infrastructure/BotSharp.OpenAPI/BackgroundServices/ConversationLogCleanupService.cs

Lines changed: 0 additions & 103 deletions
This file was deleted.

src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using BotSharp.Core.MCP.Settings;
33
using BotSharp.Core.Users.Services;
44
using BotSharp.OpenAPI.BackgroundServices;
5+
using BotSharp.OpenAPI.Hooks;
6+
using BotSharp.OpenAPI.RuleTriggers;
57
using Microsoft.AspNetCore.Authentication;
68
using Microsoft.AspNetCore.Authentication.Cookies;
79
using Microsoft.AspNetCore.Authentication.JwtBearer;
@@ -14,6 +16,8 @@
1416
using Microsoft.Net.Http.Headers;
1517
using Microsoft.OpenApi;
1618
using System.Text.Json.Serialization;
19+
using BotSharp.Abstraction.Crontab;
20+
1721
#if NET8_0
1822
using Microsoft.OpenApi.Models;
1923
#endif
@@ -37,7 +41,8 @@ public static IServiceCollection AddBotSharpOpenAPI(this IServiceCollection serv
3741
{
3842
services.AddScoped<IUserIdentity, UserIdentity>();
3943
services.AddHostedService<ConversationTimeoutService>();
40-
services.AddHostedService<ConversationLogCleanupService>();
44+
45+
services.AddCrontabServices();
4146

4247
// Add bearer authentication
4348
var schema = "MIXED_SCHEME";
@@ -224,6 +229,13 @@ private static async Task OnTicketReceivedContext(TicketReceivedContext context)
224229
}
225230
}
226231

232+
public static IServiceCollection AddCrontabServices(this IServiceCollection services)
233+
{
234+
services.AddScoped<ICrontabHook, ConversationLogCleanupCrontabHook>();
235+
services.AddScoped<ICrontabSource, ConversationLogCleanupRuleTrigger>();
236+
return services;
237+
}
238+
227239
/// <summary>
228240
/// Use Swagger/OpenAPI
229241
/// </summary>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using BotSharp.Abstraction.Conversations.Settings;
2+
using BotSharp.Abstraction.Crontab;
3+
using BotSharp.Abstraction.Crontab.Models;
4+
using BotSharp.Abstraction.Repositories;
5+
using BotSharp.OpenAPI.RuleTriggers;
6+
using Microsoft.Extensions.Hosting;
7+
using Microsoft.Extensions.Logging;
8+
using System;
9+
using System.Threading.Tasks;
10+
11+
namespace BotSharp.OpenAPI.Hooks
12+
{
13+
public class ConversationLogCleanupCrontabHook : ICrontabHook
14+
{
15+
private readonly ConversationSetting _settings;
16+
private readonly IBotSharpRepository _db;
17+
private readonly ILogger<ConversationLogCleanupCrontabHook> _logger;
18+
private readonly IHostApplicationLifetime _appLifetime;
19+
20+
public string[]? Triggers => new[] { nameof(ConversationLogCleanupRuleTrigger) };
21+
22+
public ConversationLogCleanupCrontabHook(
23+
ConversationSetting settings,
24+
IBotSharpRepository db,
25+
ILogger<ConversationLogCleanupCrontabHook> logger,
26+
IHostApplicationLifetime appLifetime)
27+
{
28+
_settings = settings;
29+
_db = db;
30+
_logger = logger;
31+
_appLifetime = appLifetime;
32+
}
33+
34+
public async Task OnCronTriggered(CrontabItem item)
35+
{
36+
var cleanSetting = _settings.CleanSetting;
37+
38+
if (cleanSetting == null || !cleanSetting.Enable || cleanSetting.LogRetentionDays <= 0) return;
39+
40+
int totalDeleted = 0;
41+
var cancellationToken = _appLifetime.ApplicationStopping;
42+
43+
while (!cancellationToken.IsCancellationRequested)
44+
{
45+
var deletedCount = await _db.DeleteOldConversationLogs(cleanSetting.LogRetentionDays, cleanSetting.LogBatchSize);
46+
if (deletedCount == 0) break;
47+
48+
totalDeleted += deletedCount;
49+
_logger.LogInformation($"Cleaned {deletedCount} conversation logs older than {cleanSetting.LogRetentionDays} days in this batch.");
50+
51+
try
52+
{
53+
// Sleep slightly to yield database resources, will throw TaskCanceledException on shutdown
54+
await Task.Delay(1000, cancellationToken);
55+
}
56+
catch (OperationCanceledException)
57+
{
58+
_logger.LogWarning("Conversation log cleanup was interrupted due to application shutdown.");
59+
break;
60+
}
61+
}
62+
63+
if (totalDeleted > 0)
64+
{
65+
_logger.LogInformation($"Successfully cleaned a total of {totalDeleted} conversation logs older than {cleanSetting.LogRetentionDays} days.");
66+
}
67+
}
68+
}
69+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using BotSharp.Abstraction.Conversations.Enums;
2+
using BotSharp.Abstraction.Crontab;
3+
using BotSharp.Abstraction.Crontab.Models;
4+
using BotSharp.Abstraction.Rules;
5+
6+
namespace BotSharp.OpenAPI.RuleTriggers
7+
{
8+
public class ConversationLogCleanupRuleTrigger : IRuleTrigger, ICrontabSource
9+
{
10+
public string Channel => ConversationChannel.Crontab;
11+
public string Name => nameof(ConversationLogCleanupRuleTrigger);
12+
public string EntityType { get; set; } = string.Empty;
13+
public string EntityId { get; set; } = string.Empty;
14+
15+
public CrontabItem GetCrontabItem()
16+
{
17+
return new CrontabItem
18+
{
19+
Title = nameof(ConversationLogCleanupRuleTrigger),
20+
Description = "Clean up old conversation logs daily",
21+
Cron = "0 6 * * *", // Run at 6:00 AM UTC (Midnight Chicago Standard Time)
22+
TriggerType = CronTabItemTriggerType.MessageQueue
23+
};
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)