Skip to content

CodeFork/FluentScheduler

 
 

Repository files navigation

logo

FluentScheduler

Automated job scheduler with fluent interface.

Usage

The job configuration is handled in a Registry class. A job is either an Action or a class that inherits IJob:

using FluentScheduler;

public class MyRegistry : Registry
{
    public MyRegistry()
    {
        // Schedule an IJob to run at an interval
        Schedule<MyJob>().ToRunNow().AndEvery(2).Seconds();

        // Schedule an IJob to run once, delayed by a specific time interval
        Schedule<MyJob>().ToRunOnceIn(5).Seconds();

        // Schedule a simple job to run at a specific time
        Schedule(() => Console.WriteLine("It's 9:15 PM now."))
            .ToRunEvery(1).Days().At(21, 15);

        // Schedule a more complex action to run immediately and on an monthly interval
        Schedule(() =>
        {
            Console.WriteLine("Complex job started at " + DateTime.Now);
            Thread.Sleep(10000);
            Console.WriteLine("Complex job ended at" + DateTime.Now);
        }).ToRunNow().AndEvery(1).Months().OnTheFirst(DayOfWeek.Monday).At(3, 0);
        
        // Schedule multiple jobs to be run in a single schedule
        Schedule<MyJob>().AndThen<MyOtherJob>().ToRunNow().AndEvery(5).Minutes();
    }
} 

To check all possible options of scheduling you can use IntelliSense on the go or check this daunting call graph (click to enlarge):

call graph

With the registry ready you then need to initialize the JobManager. This is usually done as soon as your application is loaded (in the Application_Start method of a web application for example):

protected void Application_Start()
{
    JobManager.Initialize(new MyRegistry()); 
} 

It's also possible to schedule jobs after initialization:

JobManager.AddJob(() => Console.WriteLine("Late job!"), (s) => s.ToRunEvery(5).Seconds());

Using it with ASP.NET

When using it with ASP.NET consider implementing IRegisteredObject in your job and registering it itself on HostingEnvironment (here's a great explanation on it), like:

public class SampleJob : IJob, IRegisteredObject
{
    private readonly object _lock = new object();

    private bool _shuttingDown;

    public SampleJob()
    {
        // Register this job with the hosting environment.
        // Allows for a more graceful stop of the job, in the case of IIS shutting down.
        HostingEnvironment.RegisterObject(this);
    }

    public void Execute()
    {
        lock (_lock)
        {
            if (_shuttingDown)
                return;

            // Do work, son!
        }
    }

    public void Stop(bool immediate)
    {
        // Locking here will wait for the lock in Execute to be released until this code can continue.
        lock (_lock)
        {
            _shuttingDown = true;
        }

        HostingEnvironment.UnregisterObject(this);
    }
}

Dependency Injection

FluentScheduler makes it easy to use your IoC tool of choice to create job instances. Simply implement IJobFactory.

An example using StructureMap:

using FluentScheduler;
using StructureMap;

public class StructureMapJobFactory : IJobFactory
{
    public IJob GetJobInstance<T>() where T : IJob
    {
        return ObjectFactory.Container.GetInstance<T>();
    }
}

public class MyRegistry : Registry
{
    public MyRegistry()
    {
        // Schedule an IJob to run at an interval
        Schedule<MyJob>().ToRunNow().AndEvery(2).Seconds();
    }
} 

Register the new job factory with the JobManager:

protected void Application_Start()
{
    JobManager.JobFactory = new StructureMapJobFactory();
    JobManager.Initialize(new MyRegistry()); 
}

Unexpected exceptions

To observe unhandled exceptions from your scheduled jobs, you will need to hook the JobException event on JobManager. That event will give you access to the underlying System.Threading.Tasks.Task and thrown exception details.

protected void Application_Start()
{
    JobManager.JobException += JobExceptionHandler;
    JobManager.Initialize(new JobRegistry());
}

static void JobExceptionHandler(Task sender, UnhandledExceptionEventArgs e)
{
    Log.Fatal("An error happened with a scheduled job: " + e.ExceptionObject);
}

Daylight Saving Time

Unfortunately, not unlike many schedulers, there is no Daylight Saving Time support yet.

If you are worried about your jobs not running or running twice due to that, the suggestion is to avoid troublesome time ranges or just UseUtcTime() in your registry.

Upgrading from version 3

Since the Task class is becoming ubiquitous in .NET (specially because async and await), the old ITask, TaskManager and ITaskFactory are now IJob, JobManager and IJobFactory.

It's just a rename, they work just as before.

Contributing

Feel free to open an issue or submit a pull request.

When sending a patch remember to Run All Tests (Ctrl + R, A) and Run Code Analysis on Solution (Alt + F11) if possible. And, of course, be consistent with the existing code!

About

Automated job scheduler with fluent interface.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%