Recurring Job every Seconds


#1

Hi,
is there a plan for a feature that allows of scheduling a Job that run every X second (10sec., 20 sec. etc…) ?

Thanks.

Pietro.


#2

Current implementation recurring job scheduler wakes up every minute, fetches current schedule records, and creates new background jobs based on matched recurring jobs. If we simply change this implementation to wake up every second, we’ll stress our storage with a high number of requests.

To avoid stressing, we can cache schedule records and update them each minute, for example. However, stale records will add a lot of fun cases, and we should think about them first.

On the other hand, I’m planning to implement support for constantly running processes with the following API:

public class MyProcess : IServerComponent
{
    public void Execute(CancellationToken shutdownToken)
    {
        // ...
    }
}

app.UseHangfireServer(new MyProcess()); // or so

So you’ll have an option to define such a constantly running process and use it to create background jobs even every 100 milliseconds. Hangfire already have such an infrastructure, but it is internal now for some reasons. If you are interested, I can show how to extract it to simplify the development.


#3

Hi Sergey,
if it is possible, I’m interested in solution that you have suggested.

Thanks

Regards

Pietro.


#4

After answering you, I’ve thought that you can simply use System.Threading.Timer class in your case. However, for other long-running processes you can take these sources files:

  • IServerComponent – base interface for Hangfire’s long-running processes. ServerWatchdog is the simplest implementation you can look.
  • ServerSupervisor – class that creates a new thread for server component, calls its Execute method in a loop until CancellationToken instance is not canceled.
  • AutomaticRetryServerComponentWrapper – wrapper for IServerComponent to retry Execute method in case of exception with increasing intervals.

Some of this classes are internal yet. The usage is:

class MyComponent : IServerComponent 
{  
    public void Execute(CancellationToken shutdownToken)
    {
        /* Create background jobs, poll queues or whatever */
        shutdownToken.WaitHandle.Wait(TimeSpan.FromSeconds(15));
    }
}

var component = new MyComponent();
var supervisor = new ServerSupervisor(new AutomaticRetryServerComponentWrapper(component));

supervisor.Start();   // Starts supervisor, non-blocking
supervisor.Stop();    // Non-blocking call, calls `CancellationToken.Cancel` method.
supervisor.Dispose(); // Blocking call, waits for `Thread.Join`

You can place them into Application_Start and Application_End methods.


#5

Hello
Now it has been a few years from your posting of this and I still have not seen Hangfire support to run jobs less than 1 minute? I have read several places of several in the community wanting this functionality. But now I have requirements for this and as a longtime user of Hangfire, I would like to use Hangfire for these jobs. So I am wondering if we need to do some customized coding as you proposed above? Or is there something simple that can be done to allow jobs to run every 30 seconds? Our scenario is quite simple, we just need to run very small fast running jobs <1ms every 30 seconds.


#6

I came up with a solution that works for me. I use a scheduler to repeat task under a minute and allow sleep in between. For example, I want every 30 secs. I set the scheduler to run at most 2 times. it does not run second iteration if the first iteration passed the start time for second iteration.

All my tasks follow this format -

public async Task Process(IJobCancellationToken cancellationToken)

Changed to use the scheduler hence body now looks like below where InternalProcess is the old Process.

await _processScheduler.Execute(async () => await InternalProcess(cancellationToken), DateTime.UtcNow.AddMinutes(1), MaxIterations);

Scheduler looks like below

public async Task Execute(Func action, DateTime cutoff, byte maxIterations)
{
/*
* Example: Every 30 seconds
*
* DateTime.UtcNow = 00:00:00
* Cutoff = 00:01:00
* MaxIterations = 2
*
* Interval = 30 seconds
*
*
* Iteration 1:
* Next Start =
* 00:00:30 (if process took less than 30 seconds)
* 00:01:00 (if process took more than 30 secounds) will not run again
*/

        var start = DateTime.UtcNow;
        var interval = (cutoff - start).TotalSeconds / maxIterations;

        for (byte iteration = 1; iteration <= maxIterations && iteration < byte.MaxValue - 1; ++iteration)
        {
            await action();

            var nextStart = start.AddSeconds(iteration * interval);

            while (nextStart <= DateTime.UtcNow && iteration < byte.MaxValue - 1)
            {
                ++iteration;
                nextStart = start.AddSeconds(iteration * interval);
            }

            if (nextStart >= cutoff) break;

            await Task.Delay(nextStart - DateTime.UtcNow);
        }
    }

#7

Hello Sergey,
We are using Hangfire to run our background job; but we want scheduler to constantly get updated jobs from database.
In short, we want recurring scheduler to run every second.

Could you please provide details on this?