I am trying to use Hangfire to run a recurring job in the background that polls data from another website, the issue is that I don't want the recurring job to run if the previous job is still running.
I've read through the documentation but can't seem to find the answer. Is there a way to have a recurring job that runs every 10 minutes but skips if the previous task is not done yet?
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
// Hangfire
GlobalConfiguration.Configuration
.UseSqlServerStorage("DatabaseContext");
app.UseHangfireDashboard();
app.UseHangfireServer();
RecurringJob.AddOrUpdate("site-parser", () => SiteParserService.RunAll(), Cron.Minutely, TimeZoneInfo.Utc);
ConfigureAuth(app);
}
Where does HangFire store recurring jobs? Persistent. Background jobs are created in a persistent storage – SQL Server and Redis supported officially, and a lot of other community-driven storages. You can safely restart your application and use Hangfire with ASP.NET without worrying about application pool recycles.
The call to AddOrUpdate method will create a new recurring job or update existing job with the same identifier.
Hangfire is an open-source framework that can be used to perform background processing in . Net and . Net Core applications. It is mainly used to perform background tasks such as batch/email notification, batch import of files, video/image processing, database maintaining, file purging, etc.
If you have a job that takes some time and is currently processing/running, in the Hangfire dashboard page, select the “Jobs” item in the top navigation bar. This shows entries for Enqueued, Scheduled, Processing, etc. Click the “Processing” entry, and you should see your currently processing job (or jobs).
You can use;
[DisableConcurrentExecution(10 * 60)]
attribute on the job method.
Here you can find information about this attribute: http://odinserj.net/2014/05/21/hangfire-0.8.2-released/
My solution:
namespace MyNameSpace
{
public delegate void LockWrapperDelegateVoid();
/* Job Locker. One job can work at current moment. Different jobs can work parallel */
public static class JobLocker
{
private static readonly ConcurrentDictionary<string, bool> _locks = new ConcurrentDictionary<string, bool>();
private static string LocksTryAdd(string lockerName)
{
if (string.IsNullOrEmpty(lockerName)) // lock by procedure's name (in this example = "JobProcedure")
{
lockerName = new StackFrame(2).GetMethod().Name;
}
if (!_locks.ContainsKey(lockerName))
{
_locks.TryAdd(lockerName, false);
}
return lockerName;
}
public static void LockWrapperVoid(string lockerName, LockWrapperDelegateVoid lockWrapperDelegateVoid)
{
lockerName = LocksTryAdd(lockerName);
if (!_locks[lockerName])
{
_locks[lockerName] = true;
try
{
lockWrapperDelegateVoid();
}
finally
{
_locks[lockerName] = false;
}
}
}
}
}
// USING
// JOB description
TryAddOrUpdateJob("JOB TITLE", () => JobManager.JobProcedure(), "* * * * *", TimeZoneInfo.Utc, "queueDefault"); // every one minute
public static void JobProcedure()
{
// very important. You can use "BlockArea" instead null and use one area if several jobs depend each other
// if null - area will have name like as the procedure ("JobProcedure")
JobLocker.LockWrapperVoid(null, () =>
{
//your code here
System.Threading.Thread.Sleep(2 * 1000 * 60); // timeout - 2 minutes
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With