Timer (Schedule) Trigger
Timer (Schedule) Trigger
Run jobs on a schedule to aggregate data, refresh embeddings, or send digests.
BackgroundService with PeriodicTimer
public class Scheduler : BackgroundService
{
private readonly IServiceProvider _sp;
public Scheduler(IServiceProvider sp) => _sp = sp;
protected override async Task ExecuteAsync(CancellationToken ct)
{
var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
while (await timer.WaitForNextTickAsync(ct))
{
using var scope = _sp.CreateScope();
var kernel = scope.ServiceProvider.GetRequiredService<Kernel>();
await RunJobAsync(kernel, ct);
}
}
}
- Use distributed locks (e.g., SQL/Redis) if running multiple instances.
- Record last-success and catch up on missed windows after outages.
Alternatives
Linux — cron
Run your console app on a schedule via crontab.
# Edit user crontab
crontab -e
Example entry (every 15 minutes):
*/15 * * * * /usr/bin/dotnet /opt/myapp/MyApp.dll --run-job >> /var/log/myapp/cron.log 2>&1
Minimal console app skeleton:
// Program.cs
using Microsoft.SemanticKernel;
var builder = Kernel.CreateBuilder();
// register plugins and services here
var kernel = builder.Build();
if (args.Contains("--run-job"))
{
await RunJobAsync(kernel, CancellationToken.None);
}
else
{
Console.WriteLine("Usage: MyApp --run-job");
}
static async Task RunJobAsync(Kernel kernel, CancellationToken ct)
{
// your scheduled logic; call SK functions/plugins
// await kernel.InvokeAsync(...);
}
Notes:
- Use absolute paths; redirect stdout/stderr to logs.
- Export required environment variables via
/etc/environmentor a wrapper script.
Linux — systemd timer
Prefer systemd timers over cron for better observability and unit management.
Service unit (/etc/systemd/system/myapp.service):
[Unit]
Description=MyApp scheduled job
[Service]
Type=oneshot
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/dotnet /opt/myapp/MyApp.dll --run-job
User=myapp
Group=myapp
EnvironmentFile=-/etc/myapp.env
[Install]
WantedBy=multi-user.target
Timer unit (/etc/systemd/system/myapp.timer):
[Unit]
Description=Run MyApp job every 15 minutes
[Timer]
OnCalendar=*:0/15
Persistent=true
Unit=myapp.service
[Install]
WantedBy=timers.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.timer
sudo systemctl status myapp.timer
Azure Functions — Timer Trigger (C#)
Use a Function with a CRON schedule; integrates with monitoring and scaling.
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
public static class NightlyJob
{
// Runs daily at 02:00 UTC
[FunctionName("NightlyJob")]
public static async Task Run(
[TimerTrigger("0 0 2 * * *")] TimerInfo timer,
ILogger log)
{
log.LogInformation($"NightlyJob started at: {System.DateTime.UtcNow:O}");
// Resolve your Kernel via DI (FunctionsStartup) or a factory
// var kernel = ...;
// await kernel.InvokeAsync(...);
log.LogInformation($"NightlyJob finished at: {System.DateTime.UtcNow:O}");
}
}
Notes:
- The CRON format is
{second} {minute} {hour} {day} {month} {day-of-week}. - For higher reliability, guard against overlaps (e.g., blob lease/distributed lock) and record last-success timestamps.
Pros / Cons
- Pros: Simple and predictable; good for batch and maintenance jobs.
- Cons: Overlap/drift and holidays; build guardrails to skip or delay windows.