FluentScheduler
FluentScheduler copied to clipboard
Add non-reentrant job groups
Description
I propose an extension of the scheduler that will prevent running more than one job with given name at the same time. I wast thinking about syntax like NonReentrantGroup() and NonReentrantGroup(string name):
For example:
Schedule<MyJob1>().NonReentrantGroup("Group1")).ToRunEvery(2).Seconds();
Schedule<MyJob2>().NonReentrantGroup("Group1")).ToRunEvery(5).Seconds();
Version without arguments will use task name instead of explicitly passed value:
Schedule<MyJob1>().WithName("TaskName1").NonReentrantGroup().ToRunEvery(5).Seconds();
Schedule<MyJob2>().WithName("TaskName1").NonReentrantGroup().ToRunEvery(10).Seconds();
Use case:
I have a in-application task scheduler which allows user to define recurring tasks and run them in background (under the hood it's using ToRunEvery()). Additionally user can manually start a task at given time (under the hood it uses ToRunNow()). Currently if background task is already running starting another one manually will make the two tasks run concurrently. Proposed NonReentrantByName() prevents this - at most one task with given reentrant name will run.
Currently i'm using hack-ish solution to achieve this by settings value of Reentrant property with an extension method:
private static Dictionary<string, object> _reentrantFlags = new Dictionary<string, object>();
public static Schedule NonReentrantGroup(this Schedule schedule)
{
object flag;
lock (_reentrantFlags)
{
if(!_reentrantFlags.TryGetValue(schedule.Name, out flag))
{
_reentrantFlags[schedule.Name] = flag = new object();
}
}
schedule.GetType()
.GetProperty("Reentrant", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(schedule, flag);
return schedule;
}
If you approve this i can provide PR.
I see that the code refers to the current version (master branch), but I'm definitely not tackling this one there. This one goes on the current alpha (version 6, redesign branch), which I guess you're familiar with (I remember your pull request, thanks).
I'll try my best to explain what I have in my mind, I hope it doesn't sound confusing.
The inner workings of scheduling on the redesign branch are much cleaner then what's on master, but there's a glaring flaw: it blocks when calling the user action (job), making all schedules non-reentrant.
Despite having already documented that, I want to fix it.
But this time I want to make the 'non-reetrancy' more flexible, letting the user provide the lock, something like:
var myLock = new object();
// make it non-reentrant, internally creating a new object for the lock and using it just for this schedule
schedule1.NonReentrant();
// make it non-reentrant, but sharing the reentrancy lock provided by the library user
schedule2.NonReentrant(myLock);
schedule3.NonReentrant(myLock);
That should make it trivial to achieve what you desire. Combine that with grouping schedules and should be even easier.