Skip to content

Commit 7920969

Browse files
authored
Merge pull request #777 from hchen2020/master
Fix Mongo version issue.
2 parents 7f16eae + 35e7cd3 commit 7920969

File tree

26 files changed

+392
-15
lines changed

26 files changed

+392
-15
lines changed

src/Infrastructure/BotSharp.Abstraction/Agents/Enums/BuiltInAgentId.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,14 @@ public class BuiltInAgentId
5151
/// Evaluate prompt and conversation
5252
/// </summary>
5353
public const string Evaluator = "dfd9b46d-d00c-40af-8a75-3fbdc2b89869";
54+
55+
/// <summary>
56+
/// Translates user-defined natural language rules into programmatic code
57+
/// </summary>
58+
public const string RuleEncoder = "6acfb93c-3412-402e-9ba5-c5d3cd8f0161";
59+
60+
/// <summary>
61+
/// Schedule job
62+
/// </summary>
63+
public const string Crontab = "c2o139da-a62a-4355-8605-fdf0ffaca58e";
5464
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ public class ConversationChannel
77
public const string Phone = "phone";
88
public const string Messenger = "messenger";
99
public const string Email = "email";
10+
public const string Cron = "cron";
1011
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace BotSharp.Abstraction.Infrastructures;
2+
3+
public interface IDistributedLocker
4+
{
5+
bool Lock(string resource, Action action, int timeout = 30);
6+
Task<bool> LockAsync(string resource, Func<Task> action, int timeout = 30);
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using BotSharp.Core.Crontab.Models;
2+
3+
namespace BotSharp.Core.Crontab.Abstraction;
4+
5+
public interface ICrontabHook
6+
{
7+
Task OnCronTriggered(CrontabItem item);
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using BotSharp.Core.Crontab.Models;
2+
3+
namespace BotSharp.Core.Crontab.Abstraction;
4+
5+
public interface ICrontabService
6+
{
7+
Task<List<CrontabItem>> GetCrontable();
8+
Task ScheduledTimeArrived(CrontabItem item);
9+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<None Remove="data\agents\c2o139da-a62a-4355-8605-fdf0ffaca58e\agent.json" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<Content Include="data\agents\c2o139da-a62a-4355-8605-fdf0ffaca58e\agent.json">
15+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
16+
</Content>
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
21+
<ProjectReference Include="..\BotSharp.Core\BotSharp.Core.csproj" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<PackageReference Include="NCrontab" Version="3.3.3" />
26+
</ItemGroup>
27+
28+
</Project>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*****************************************************************************
2+
Copyright 2024 Written by Haiping Chen. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
******************************************************************************/
16+
17+
namespace BotSharp.Core.Crontab;
18+
19+
/// <summary>
20+
/// Crontab plugin is a time-based job scheduler in agent framework.
21+
/// The cron system is used for automating repetitive tasks, such as trigger AI Agent to do specific task periodically.
22+
/// </summary>
23+
public class CrontabPlugin : IBotSharpPlugin
24+
{
25+
public string Id => "3155c15e-28d3-43f7-8ead-fc43324ec21a";
26+
public string Name => "BotSharp Crontab";
27+
public string Description => "Crontab plugin is a time-based job scheduler in agent framework. The cron system is used to trigger AI Agent to do specific task periodically.";
28+
public string IconUrl => "https://icon-library.com/images/stop-watch-icon/stop-watch-icon-10.jpg";
29+
30+
public string[] AgentIds =
31+
[
32+
BuiltInAgentId.Crontab
33+
];
34+
35+
public void RegisterDI(IServiceCollection services, IConfiguration config)
36+
{
37+
services.AddScoped<ICrontabService, CrontabService>();
38+
services.AddHostedService<CrontabWatcher>();
39+
}
40+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace BotSharp.Core.Crontab.Models;
2+
3+
public class CrontabItem
4+
{
5+
public string UserId { get; set; } = null!;
6+
public string AgentId { get; set; } = null!;
7+
public string Topic { get; set; } = null!;
8+
public string Cron { get; set; } = null!;
9+
10+
public override string ToString()
11+
{
12+
return $"AgentId: {AgentId}, UserId: {UserId}, Topic: {Topic}";
13+
}
14+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*****************************************************************************
2+
Copyright 2024 Written by Haiping Chen. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
******************************************************************************/
16+
17+
using BotSharp.Abstraction.Agents.Enums;
18+
using BotSharp.Core.Crontab.Models;
19+
using BotSharp.Core.Infrastructures;
20+
21+
22+
/*****************************************************************************
23+
Copyright 2024 Written by Haiping Chen. All Rights Reserved.
24+
25+
Licensed under the Apache License, Version 2.0 (the "License");
26+
you may not use this file except in compliance with the License.
27+
You may obtain a copy of the License at
28+
29+
http://www.apache.org/licenses/LICENSE-2.0
30+
31+
Unless required by applicable law or agreed to in writing, software
32+
distributed under the License is distributed on an "AS IS" BASIS,
33+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34+
See the License for the specific language governing permissions and
35+
limitations under the License.
36+
******************************************************************************/
37+
38+
using Microsoft.Extensions.Logging;
39+
40+
namespace BotSharp.Core.Crontab.Services;
41+
42+
/// <summary>
43+
/// The Crontab service schedules distributed events based on the execution times provided by users.
44+
/// In a scalable environment, distributed locks are used to ensure that each event is triggered only once.
45+
/// </summary>
46+
public class CrontabService : ICrontabService
47+
{
48+
private readonly IServiceProvider _services;
49+
private ILogger _logger;
50+
51+
public CrontabService(IServiceProvider services, ILogger<CrontabService> logger)
52+
{
53+
_services = services;
54+
_logger = logger;
55+
}
56+
57+
public async Task<List<CrontabItem>> GetCrontable()
58+
{
59+
return
60+
[
61+
new CrontabItem
62+
{
63+
Cron = "*/30 * * * * *",
64+
AgentId = BuiltInAgentId.AIAssistant,
65+
}
66+
];
67+
}
68+
69+
public async Task ScheduledTimeArrived(CrontabItem item)
70+
{
71+
_logger.LogInformation("ScheduledTimeArrived");
72+
await HookEmitter.Emit<ICrontabHook>(_services, async hook =>
73+
await hook.OnCronTriggered(item)
74+
);
75+
await Task.Delay(1000 * 10);
76+
}
77+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using BotSharp.Abstraction.Infrastructures;
2+
using Microsoft.Extensions.Hosting;
3+
using Microsoft.Extensions.Logging;
4+
using NCrontab;
5+
6+
namespace BotSharp.Core.Crontab.Services;
7+
8+
public class CrontabWatcher : BackgroundService
9+
{
10+
private readonly ILogger _logger;
11+
private readonly IServiceProvider _services;
12+
13+
public CrontabWatcher(IServiceProvider services, ILogger<CrontabWatcher> logger)
14+
{
15+
_logger = logger;
16+
_services = services;
17+
}
18+
19+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
20+
{
21+
_logger.LogInformation("Crontab Watcher background service is running.");
22+
23+
using (var scope = _services.CreateScope())
24+
{
25+
var locker = scope.ServiceProvider.GetRequiredService<IDistributedLocker>();
26+
27+
while (!stoppingToken.IsCancellationRequested)
28+
{
29+
var delay = Task.Delay(1000, stoppingToken);
30+
31+
await locker.LockAsync("CrontabWatcher", async () =>
32+
{
33+
await RunCronChecker(scope.ServiceProvider);
34+
});
35+
36+
await delay;
37+
}
38+
39+
_logger.LogWarning("Crontab Watcher background service is stopped.");
40+
}
41+
}
42+
43+
private async Task RunCronChecker(IServiceProvider services)
44+
{
45+
var cron = services.GetRequiredService<ICrontabService>();
46+
var crons = await cron.GetCrontable();
47+
foreach (var item in crons)
48+
{
49+
var schedule = CrontabSchedule.Parse(item.Cron, new CrontabSchedule.ParseOptions
50+
{
51+
IncludingSeconds = true // Ensure you account for seconds
52+
});
53+
54+
// Get the current time
55+
var currentTime = DateTime.UtcNow;
56+
57+
// Get the next occurrence from the schedule
58+
var nextOccurrence = schedule.GetNextOccurrence(currentTime.AddSeconds(-1));
59+
60+
// Check if the current time matches the schedule
61+
bool matches = currentTime >= nextOccurrence && currentTime < nextOccurrence.AddSeconds(1);
62+
63+
if (matches)
64+
{
65+
_logger.LogInformation($"The current time matches the cron expression {item}");
66+
cron.ScheduledTimeArrived(item);
67+
}
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)