Skip to content

Commit 5b47e68

Browse files
authored
Merge pull request #834 from hchen2020/master
ICrontabSource
2 parents adc3cd5 + 133e5f2 commit 5b47e68

File tree

15 files changed

+119
-32
lines changed

15 files changed

+119
-32
lines changed

src/Infrastructure/BotSharp.Abstraction/Agents/IAgentRuleHook.cs

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

src/Infrastructure/BotSharp.Abstraction/Conversations/Enums/ConversationChannel.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ public class ConversationChannel
55
public const string WebChat = "webchat";
66
public const string OpenAPI = "openapi";
77
public const string Phone = "phone";
8+
public const string SMS = "sms";
89
public const string Messenger = "messenger";
910
public const string Email = "email";
10-
public const string Cron = "cron";
11+
public const string Crontab = "crontab";
1112
public const string Database = "database";
1213
}

src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItem.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class CrontabItem : ScheduleTaskArgs
2323
[JsonPropertyName("expire_seconds")]
2424
public int ExpireSeconds { get; set; } = 60;
2525

26+
[JsonPropertyName("last_execution_time")]
27+
public DateTime? LastExecutionTime { get; set; }
28+
2629
[JsonPropertyName("created_time")]
2730
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;
2831

src/Infrastructure/BotSharp.Core.Crontab/Abstraction/ICrontabHook.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,12 @@ namespace BotSharp.Core.Crontab.Abstraction;
22

33
public interface ICrontabHook
44
{
5-
Task OnCronTriggered(CrontabItem item);
5+
Task OnCronTriggered(CrontabItem item)
6+
=> Task.CompletedTask;
7+
8+
Task OnTaskExecuting(CrontabItem item)
9+
=> Task.CompletedTask;
10+
11+
Task OnTaskExecuted(CrontabItem item)
12+
=> Task.CompletedTask;
613
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace BotSharp.Core.Crontab.Abstraction;
2+
3+
/// <summary>
4+
/// Provide a cron source for the crontab service.
5+
/// </summary>
6+
public interface ICrontabSource
7+
{
8+
CrontabItem GetCrontabItem();
9+
}

src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,28 @@ public async Task<List<CrontabItem>> GetCrontable()
3939
{
4040
var repo = _services.GetRequiredService<IBotSharpRepository>();
4141
var crontable = repo.GetCrontabItems(CrontabItemFilter.Empty());
42-
return crontable.Items.ToList();
42+
43+
// Add fixed crontab items from cronsources
44+
var fixedCrantabItems = crontable.Items.ToList();
45+
var cronsources = _services.GetServices<ICrontabSource>();
46+
foreach (var source in cronsources)
47+
{
48+
var item = source.GetCrontabItem();
49+
fixedCrantabItems.Add(source.GetCrontabItem());
50+
}
51+
52+
return fixedCrantabItems;
4353
}
4454

4555
public async Task ScheduledTimeArrived(CrontabItem item)
4656
{
4757
_logger.LogDebug($"ScheduledTimeArrived {item}");
4858

4959
await HookEmitter.Emit<ICrontabHook>(_services, async hook =>
50-
await hook.OnCronTriggered(item)
51-
);
52-
await Task.Delay(1000 * 10);
60+
{
61+
await hook.OnTaskExecuting(item);
62+
await hook.OnCronTriggered(item);
63+
await hook.OnTaskExecuted(item);
64+
});
5365
}
5466
}

src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabWatcher.cs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
2424
{
2525
var locker = scope.ServiceProvider.GetRequiredService<IDistributedLocker>();
2626

27-
/*while (!stoppingToken.IsCancellationRequested)
27+
while (!stoppingToken.IsCancellationRequested)
2828
{
29-
var delay = Task.Delay(1000, stoppingToken);
29+
var delay = Task.Delay(1000 * 10, stoppingToken);
3030

3131
await locker.LockAsync("CrontabWatcher", async () =>
3232
{
3333
await RunCronChecker(scope.ServiceProvider);
3434
});
3535

3636
await delay;
37-
}*/
37+
}
3838

3939
_logger.LogWarning("Crontab Watcher background service is stopped.");
4040
}
@@ -58,10 +58,24 @@ private async Task RunCronChecker(IServiceProvider services)
5858
// Get the current time
5959
var currentTime = DateTime.UtcNow;
6060

61+
// Get the last occurrence from the schedule
62+
var lastOccurrence = GetLastOccurrence(schedule);
63+
6164
// Get the next occurrence from the schedule
6265
var nextOccurrence = schedule.GetNextOccurrence(currentTime.AddSeconds(-1));
6366

64-
// Check if the current time matches the schedule
67+
// Get the previous occurrence from the execution log
68+
var previousOccurrence = item.LastExecutionTime;
69+
70+
// First check if this occurrence was already triggered
71+
if (previousOccurrence.HasValue &&
72+
previousOccurrence.Value >= lastOccurrence &&
73+
previousOccurrence.Value < nextOccurrence.AddSeconds(1))
74+
{
75+
continue;
76+
}
77+
78+
// Then check if the current time matches the schedule
6579
bool matches = currentTime >= nextOccurrence && currentTime < nextOccurrence.AddSeconds(1);
6680

6781
if (matches)
@@ -72,9 +86,21 @@ private async Task RunCronChecker(IServiceProvider services)
7286
}
7387
catch (Exception ex)
7488
{
75-
_logger.LogWarning($"Error when running cron task ({item.ConversationId}, {item.Title}, {item.Cron}): {ex.Message}\r\n{ex.InnerException}");
89+
_logger.LogError($"Error when running cron task ({item.Title}, {item.Cron}): {ex.Message}");
7690
continue;
7791
}
7892
}
7993
}
94+
95+
private DateTime GetLastOccurrence(CrontabSchedule schedule)
96+
{
97+
var nextOccurrence = schedule.GetNextOccurrence(DateTime.UtcNow);
98+
var afterNextOccurrence = schedule.GetNextOccurrence(nextOccurrence);
99+
var interval = afterNextOccurrence - nextOccurrence;
100+
if (interval.TotalMinutes < 10)
101+
{
102+
throw new ArgumentException("The minimum interval must be at least 10 minutes.");
103+
}
104+
return nextOccurrence - interval;
105+
}
80106
}

src/Infrastructure/BotSharp.Core.Rules/Engines/RuleEngine.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@ public async Task Triggered(IRuleTrigger trigger, string data)
4545
{
4646
var conv = await convService.NewConversation(new Conversation
4747
{
48+
Channel = trigger.Channel,
49+
Title = data,
4850
AgentId = agent.Id
4951
});
5052

5153
var message = new RoleDialogModel(AgentRole.User, data);
5254

5355
var states = new List<MessageState>
5456
{
55-
new("channel", ConversationChannel.Database),
57+
new("channel", trigger.Channel),
5658
new("channel_id", trigger.EntityId)
5759
};
5860
convService.SetConversationId(conv.Id, states);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace BotSharp.Core.Rules.Triggers;
2+
3+
public interface IRuleConfig
4+
{
5+
}

src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
</ItemGroup>
4848

4949
<ItemGroup>
50+
<ProjectReference Include="..\BotSharp.Core.Rules\BotSharp.Core.Rules.csproj" />
5051
<ProjectReference Include="..\BotSharp.Core\BotSharp.Core.csproj" />
5152
</ItemGroup>
5253

0 commit comments

Comments
 (0)