Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,17 @@ public class CrontabItem : ScheduleTaskArgs
[JsonPropertyName("created_time")]
public DateTime CreatedTime { get; set; } = DateTime.UtcNow;

[JsonPropertyName("trigger_type")]
public CronTabItemTriggerType TriggerType { get; set; } = CronTabItemTriggerType.BackgroundWatcher;

public override string ToString()
{
return $"{Title}: {Description} [AgentId: {AgentId}, UserId: {UserId}]";
}
}

public enum CronTabItemTriggerType
{
BackgroundWatcher,
OpenAPI
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
var subscriber = scope.ServiceProvider.GetRequiredService<IEventSubscriber>();
var cron = scope.ServiceProvider.GetRequiredService<ICrontabService>();
var crons = await cron.GetCrontable();
foreach (var item in crons)
var allowedCrons = crons.Where(cron => cron.TriggerType == CronTabItemTriggerType.BackgroundWatcher).ToList();
foreach (var item in allowedCrons)
{
_ = Task.Run(async () =>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using NCrontab;

namespace BotSharp.Core.Crontab.Services
{
public static class CrontabItemExtension
{
public static bool CheckNextOccurrenceEveryOneMinute(this CrontabItem item)
{
// strip seconds from cron expression
item.Cron = string.Join(" ", item.Cron.Split(' ').TakeLast(5));
var schedule = CrontabSchedule.Parse(item.Cron, new CrontabSchedule.ParseOptions
{
IncludingSeconds = false // Ensure you account for seconds
});

var currentTime = DateTime.UtcNow;
var currentMinute = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day,
currentTime.Hour, currentTime.Minute, 0, DateTimeKind.Utc);

var oneMinuteAgo = currentMinute.AddMinutes(-1);
var nextOccurrence = schedule.GetNextOccurrence(oneMinuteAgo);

return nextOccurrence == currentMinute;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ private async Task RunCronChecker(IServiceProvider services)
{
var cron = services.GetRequiredService<ICrontabService>();
var crons = await cron.GetCrontable();
var allowedCrons = crons.Where(cron => cron.TriggerType == CronTabItemTriggerType.BackgroundWatcher).ToList();
var settings = services.GetRequiredService<CrontabSettings>();
var publisher = services.GetService<IEventPublisher>();

foreach (var item in crons)
foreach (var item in allowedCrons)
{
_logger.LogDebug($"[{DateTime.UtcNow}] Cron task ({item.Title}, {item.Cron}), Last Execution Time: {item.LastExecutionTime}");

Expand Down
3 changes: 2 additions & 1 deletion src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>
Expand Down Expand Up @@ -35,6 +35,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BotSharp.Core.Crontab\BotSharp.Core.Crontab.csproj" />
<ProjectReference Include="..\BotSharp.Core\BotSharp.Core.csproj" />
<ProjectReference Include="..\BotSharp.Logger\BotSharp.Logger.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using BotSharp.Abstraction.Crontab;
using BotSharp.Abstraction.Crontab.Models;
using BotSharp.Core.Crontab.Services;
using BotSharp.OpenAPI.Controllers.Crontab.Models;

namespace BotSharp.OpenAPI.Controllers;

Expand Down Expand Up @@ -42,4 +45,60 @@ public async Task<bool> RunCrontab(string name)
return false;
}
}

/// <summary>
/// As the Dkron job trigger API, run every 1 minutes
/// </summary>
/// <returns></returns>
[HttpPost("/crontab/scheduling-per-minute")]
public async Task<CrontabSchedulingResult> SchedulingCrontab()
{
var result = new CrontabSchedulingResult();
var allowedCrons = await GetCrontabItems();

foreach (var item in allowedCrons)
{
if (item.CheckNextOccurrenceEveryOneMinute())
{
_logger.LogInformation("Crontab: {0}, One occurrence was matched, Beginning execution...", item.Title);
Task.Run(() => ExecuteTimeArrivedItem(item, _services));
result.OccurrenceMatchedItems.Add(item.Title);
}
}

await Task.Delay(1000);
return result;
}

private async Task<List<CrontabItem>> GetCrontabItems(string? title = null)
{
var crontabService = _services.GetRequiredService<ICrontabService>();
var crons = await crontabService.GetCrontable();
var allowedCrons = crons.Where(cron => cron.TriggerType == CronTabItemTriggerType.OpenAPI).ToList();

if (title is null)
{
return allowedCrons;
}

return allowedCrons.Where(cron => cron.Title.IsEqualTo(title)).ToList();
}

private async Task<bool> ExecuteTimeArrivedItem(CrontabItem item, IServiceProvider services)
{
try
{
using var scope = services.CreateScope();
var crontabService = scope.ServiceProvider.GetRequiredService<ICrontabService>();
_logger.LogInformation($"Start running crontab {item.Title}");
await crontabService.ScheduledTimeArrived(item);
_logger.LogInformation($"Complete running crontab {item.Title}");
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error when running crontab {item.Title}");
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BotSharp.OpenAPI.Controllers.Crontab.Models;

public class CrontabSchedulingResult
{
public List<string> OccurrenceMatchedItems { get; set; } = new List<string>();
}
Loading