我的工作执行了任意次数,即使只安排了一次
My job executes an arbitrary number of times even though only scheduled once
- Hangfire 1.6.17
- SQL 服务器 2016 (13.0.4206.0)
我有一个使用 OWIN 托管 Hangfire 服务器的 C# 控制台应用程序,如下所示:
public class Startup
{
public void Configuration(IAppBuilder aAppBuilder)
{
//How we want to use Hangfire
GlobalConfiguration.Configuration
.UseSqlServerStorage("HangfireConnectionString")
.UseConsole(new ConsoleOptions
{
BackgroundColor = "#0d3163",
TextColor = "#ffffff",
TimestampColor = "#00aad7"
});
//Read the settings file
SettingsIni iniSettings = new SettingsIni(GeneralHelper.GetAppPath() + "settings.ini");
//Dashboard
aAppBuilder.UseHangfireDashboard(iniSettings.HttpServer.Path, new DashboardOptions
{
AppPath = "/",
Authorization = new[]
{
new HangfireAuthorizationFilter()
}
});
//Server
BackgroundJobServerOptions serverOptions = new BackgroundJobServerOptions
{
Queues = GeneralHelper.GetQueueNames(iniSettings).ToArray()
};
aAppBuilder.UseHangfireServer(serverOptions);
//Ensure our recurring tasks are running if required.
if (iniSettings.Behaviour.DoPlatformManagerInit) TpHangfireJobsManager.Initialise();
}
}
作为应用程序启动的一部分,我添加了一个 fire and forget 作业,如下所示:
BackgroundJob.Enqueue<TpHardLinkAttachmentsForEmailMessagesWatchDog>(aX => aX.ExecuteJob(null, new TpHardLinkAttachmentsForEmailMessagesWatchDogParamsInput
{
ForYear = 2017
}));
正在执行的方法是:
public override void ExecuteJob(PerformContext aContext, TpHardLinkAttachmentsForEmailMessagesWatchDogParamsInput aParams)
{
Trace.WriteLine($"Params: {aParams.ForYear}");
DateTime startDate = new DateTime(aParams.ForYear, 1, 1);
DateTime endDate = new DateTime(aParams.ForYear, 1, 31);
//Start with a huge record id so we can work backwards
long currRecId = int.MaxValue;
//Keep getting records until we are done
while (true)
{
//Find all records that have to be processed. We start with the highest record id in the year and then work backwards until we run out of record
long idLast = currRecId;
Trace.WriteLine($"Id Last: {idLast}");
List<EmailActivityTableModel> recordsToProcess = _EmailActivityDomainService.GetWhere(
aR => aR.Id < idLast &&
aR.Created >= startDate &&
aR.Created <= endDate &&
(
aR.ExternalIdKind == ExternalIdKindEnum.Family ||
aR.ExternalIdKind == ExternalIdKindEnum.Individual
) &&
(
aR.ExternalId != "" ||
aR.ExternalId != "-1"
) //Ensure we have an external identifier
).OrderByDescending(aR => aR.Id)
.Take(5).ToList();
//We are done if we did not find any records
if (recordsToProcess.Count == 0)
break;
aContext.WriteLine("Process {0} records.", recordsToProcess.Count);
Trace.WriteLine($"Record Count: {recordsToProcess.Count}");
foreach (EmailActivityTableModel emailActivityRecord in recordsToProcess)
{
aContext.WriteLine(emailActivityRecord.Id);
currRecId = emailActivityRecord.Id;
Trace.WriteLine($"Curr Rec Id: {emailActivityRecord.Id}");
}
//TESTING - Bail after the first iteration so 5 records
return;
}
}
该方法所做的就是最终从数据库中读取一些记录并输出主键。我看到的是该方法被多次调用(数量因控制台应用程序的每个 运行 而异)并且我看到以下内容:
不过我在 HangFire 中只看到一个成功的任务:
我没有异常(注意每次都完成所有 5 次迭代)因此作业不会因此而重新启动。
所以我的问题是为什么我的 ExecuteJob() 被调用了这么多次?
为了完整起见,我正在回答这个问题。
原来我收到了一个异常位,它没有显示在我的日志中。我最终通过添加 coloured console logger.
找到了它
我正在使用名为 HangFire.Console which has an issue with the attribute DisableConcurrentExecution as detailed here 的第三方软件包。将该属性交换为 Mutex,现在一切正常。
- Hangfire 1.6.17
- SQL 服务器 2016 (13.0.4206.0)
我有一个使用 OWIN 托管 Hangfire 服务器的 C# 控制台应用程序,如下所示:
public class Startup
{
public void Configuration(IAppBuilder aAppBuilder)
{
//How we want to use Hangfire
GlobalConfiguration.Configuration
.UseSqlServerStorage("HangfireConnectionString")
.UseConsole(new ConsoleOptions
{
BackgroundColor = "#0d3163",
TextColor = "#ffffff",
TimestampColor = "#00aad7"
});
//Read the settings file
SettingsIni iniSettings = new SettingsIni(GeneralHelper.GetAppPath() + "settings.ini");
//Dashboard
aAppBuilder.UseHangfireDashboard(iniSettings.HttpServer.Path, new DashboardOptions
{
AppPath = "/",
Authorization = new[]
{
new HangfireAuthorizationFilter()
}
});
//Server
BackgroundJobServerOptions serverOptions = new BackgroundJobServerOptions
{
Queues = GeneralHelper.GetQueueNames(iniSettings).ToArray()
};
aAppBuilder.UseHangfireServer(serverOptions);
//Ensure our recurring tasks are running if required.
if (iniSettings.Behaviour.DoPlatformManagerInit) TpHangfireJobsManager.Initialise();
}
}
作为应用程序启动的一部分,我添加了一个 fire and forget 作业,如下所示:
BackgroundJob.Enqueue<TpHardLinkAttachmentsForEmailMessagesWatchDog>(aX => aX.ExecuteJob(null, new TpHardLinkAttachmentsForEmailMessagesWatchDogParamsInput
{
ForYear = 2017
}));
正在执行的方法是:
public override void ExecuteJob(PerformContext aContext, TpHardLinkAttachmentsForEmailMessagesWatchDogParamsInput aParams)
{
Trace.WriteLine($"Params: {aParams.ForYear}");
DateTime startDate = new DateTime(aParams.ForYear, 1, 1);
DateTime endDate = new DateTime(aParams.ForYear, 1, 31);
//Start with a huge record id so we can work backwards
long currRecId = int.MaxValue;
//Keep getting records until we are done
while (true)
{
//Find all records that have to be processed. We start with the highest record id in the year and then work backwards until we run out of record
long idLast = currRecId;
Trace.WriteLine($"Id Last: {idLast}");
List<EmailActivityTableModel> recordsToProcess = _EmailActivityDomainService.GetWhere(
aR => aR.Id < idLast &&
aR.Created >= startDate &&
aR.Created <= endDate &&
(
aR.ExternalIdKind == ExternalIdKindEnum.Family ||
aR.ExternalIdKind == ExternalIdKindEnum.Individual
) &&
(
aR.ExternalId != "" ||
aR.ExternalId != "-1"
) //Ensure we have an external identifier
).OrderByDescending(aR => aR.Id)
.Take(5).ToList();
//We are done if we did not find any records
if (recordsToProcess.Count == 0)
break;
aContext.WriteLine("Process {0} records.", recordsToProcess.Count);
Trace.WriteLine($"Record Count: {recordsToProcess.Count}");
foreach (EmailActivityTableModel emailActivityRecord in recordsToProcess)
{
aContext.WriteLine(emailActivityRecord.Id);
currRecId = emailActivityRecord.Id;
Trace.WriteLine($"Curr Rec Id: {emailActivityRecord.Id}");
}
//TESTING - Bail after the first iteration so 5 records
return;
}
}
该方法所做的就是最终从数据库中读取一些记录并输出主键。我看到的是该方法被多次调用(数量因控制台应用程序的每个 运行 而异)并且我看到以下内容:
不过我在 HangFire 中只看到一个成功的任务:
我没有异常(注意每次都完成所有 5 次迭代)因此作业不会因此而重新启动。
所以我的问题是为什么我的 ExecuteJob() 被调用了这么多次?
为了完整起见,我正在回答这个问题。
原来我收到了一个异常位,它没有显示在我的日志中。我最终通过添加 coloured console logger.
找到了它我正在使用名为 HangFire.Console which has an issue with the attribute DisableConcurrentExecution as detailed here 的第三方软件包。将该属性交换为 Mutex,现在一切正常。