Projektdateien hinzufügen.

This commit is contained in:
mr_sc
2026-08-19 19:27:41 +02:00
parent 0889f1f6c7
commit 7fe54c0785
32 changed files with 2406 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace FileInterface.Scheduler
{
public sealed class CronScheduler : IDisposable
{
private readonly CronJobRepository _repository;
private readonly CronJobExecutor _executor;
private readonly JobLog _log;
private readonly ConcurrentDictionary<string, byte> _running = new ConcurrentDictionary<string, byte>(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<string, string> _lastMinuteRun = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private Timer _timer;
private int _checking;
public CronScheduler(CronJobRepository repository, CronJobExecutor executor, JobLog log)
{
_repository = repository;
_executor = executor;
_log = log;
}
public void Start()
{
if (_timer != null) return;
_timer = new Timer(CheckDueJobs, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
}
public bool RunNow(string jobId)
{
CronJobConfig job = _repository.GetById(jobId);
if (job == null) return false;
QueueExecution(job, "manual");
return true;
}
public IList<string> GetRunningJobIds()
{
return new List<string>(_running.Keys);
}
private void CheckDueJobs(object state)
{
if (Interlocked.Exchange(ref _checking, 1) == 1) return;
try
{
DateTime now = DateTime.Now;
string minuteStamp = now.ToString("yyyyMMddHHmm");
foreach (CronJobConfig job in _repository.GetAll())
{
if (!job.Enabled) continue;
try
{
CronExpression cron = CronExpression.Parse(job.Cron);
if (!cron.IsMatch(now)) continue;
string previous;
if (_lastMinuteRun.TryGetValue(job.Id, out previous) && previous == minuteStamp) continue;
_lastMinuteRun[job.Id] = minuteStamp;
QueueExecution(job, "cron " + job.Cron);
}
catch (Exception ex)
{
_log.Error(job, "Invalid cron/configuration: " + ex.Message);
}
}
}
finally { Interlocked.Exchange(ref _checking, 0); }
}
private void QueueExecution(CronJobConfig job, string reason)
{
byte ignored;
if (!_running.TryAdd(job.Id, 0))
{
_log.Info(job, "Skipped " + reason + " start because this job is still running.");
return;
}
Task.Run(() =>
{
try
{
_log.Info(job, "Job started (" + reason + ").");
_executor.Execute(job);
_log.Info(job, "Job finished.");
}
catch (Exception ex)
{
_log.Error(job, "Job crashed: " + ex);
}
finally { _running.TryRemove(job.Id, out ignored); }
});
}
public void Dispose()
{
Timer timer = _timer;
_timer = null;
if (timer != null) timer.Dispose();
}
}
}