在数据库中记录 Hangfire RecurringJob 的执行?
Logging the execution of a Hangfire RecurringJob in database?
我已经为我的 ASP.NET 项目设置 hangfire 成功,即在我的数据库中创建了 11 个 Hangfire 表。我在项目 Global.asax
的 Application_Start()
中尝试了以下命令:
namespace myAPI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start(
{
System.Diagnostics.Debug.WriteLine("Recurring job will be set up.");
RecurringJob.AddOrUpdate(
"some-id",
() => System.Diagnostics.Debug.WriteLine("Job instance started at " +
DateTime.Now)),
"*/2 * * * 1-5");
}
}
}
遗憾的是,在 Visual Studio 的 window Output > Debug 中,我只看到 Reccuring job will be set up.
,此后什么也没有。但是,SELECT * FROM [myContext].[HangFire].[Set]
显示我
Key Score Value ExpireAt
recurring-jobs 1579116240 some-id NULL
到目前为止一切顺利,这意味着作业确实设置好了。
但是 如何在每次执行 RecurringJob 时在我的数据库 中记录 ? 我是否正确地假设 Hangfire 可以不是开箱即用,我必须自己在箭头功能中记录它吗?还是有更优雅的方式?
旁边的问题:为什么我在的重复工作中看不到System.Diagnostics.Debug.WriteLine
的任何输出?
参考资料
- Hangfire doesn't create tables in IIS
- Official hangfire.io docu on recurrent tasks
因此 cron 已设置为启动 At every 2nd minute on every day-of-week from Monday through Friday。我假设您正在等待作业执行并且它是在正确的 window 时间。
我在网上找到的大部分参考资料都表明你可以做到。
RecurringJob.AddOrUpdate(() => Console.WriteLine("This job will execute once in every minute"), Cron.Minutely);
也许你需要把点排列得更好一点才能写入 vs 控制台。
还有一个管理门户,可以对其进行配置以查看什么是开始 运行 以及何时开始。
我有以下设置。
Global.asax.cs
protected void Application_Start()
{
HangfireJobsConfig.Register();
}
public class HangfireJobsConfig
{
public static void Register()
{
if (App1Config.RunHangfireService)
{
JobStorage.Current = new SqlServerStorage(App1Config.DefaultConnectionStringName.Split('=').Last());
GlobalConfiguration.Configuration.UseConsole();
RecurringJob.AddOrUpdate("RunJob1", () => RunJob1(null), Cron.MinuteInterval(App1Config.RunJob1Interval));
RecurringJob.AddOrUpdate("RunJob2", () => RunJob2(null), Cron.MinuteInterval(App1Config.RunJob2Interval));
}
}
[AutomaticRetry(Attempts = 0, Order = 1)]
public static void RunJob1(PerformContext context)
{
//dostuff
}
[AutomaticRetry(Attempts = 0, Order = 2)]
public static void RunJob2(PerformContext context)
{
//do stuff
}
}
Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
ConfigureHangFire(app);
}
public void ConfigureHangFire(IAppBuilder app)
{
if (App1Config.RunHangfireService)
{
GlobalConfiguration.Configuration.UseSqlServerStorage(
AppiConfig.DefaultConnectionStringName.Split('=').Last());
GlobalConfiguration.Configuration.UseConsole();
app.UseHangfireServer();
var options = new DashboardOptions
{
AuthorizationFilters = new[]
{
new AuthorizationFilter { Roles = "Inventory" }
}
};
app.UseHangfireDashboard("/hangfire", options);
}
}
}
您可以开箱即用 SeriLog with Hangfire。 Serilog 带有不同的接收器,例如Serilog.Sinks.MSSqlServer
。您可以在 startup.cs
:
中进行配置
using Serilog;
using Serilog.Sinks.MSSqlServer;
Log.Logger = new LoggerConfiguration()
.WriteTo
.MSSqlServer(
connectionString: hangfireConnectionString,
tableName: "Logs",
autoCreateSqlTable: true
).CreateLogger();
// will display any issues with Serilog config. comment out in prod.
Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));
GlobalConfiguration.Configuration
.UseSqlServerStorage(hangfireConnectionString)
.UseSerilogLogProvider();
安排工作后,您可以使用
记录它
Log.Information(string.Format("Hanfire Job Scheduled at {0}", DateTime.Now));
Hangfire 包含 job filters 的概念(类似于 ASP.NET MVC 的 Action Filters)。对于您的用例,您将定义一个写入数据库的案例(根据您的需要进行调整):
using Hangfire.Common;
using Hangfire.Server;
class LogCompletionAttribute : JobFilterAttribute, IServerFilter
{
public void OnPerforming(PerformingContext filterContext)
{
// Code here if you care when the execution **has begun**
}
public void OnPerformed(PerformedContext context)
{
// Check that the job completed successfully
if (!context.Canceled && context.Exception != null)
{
// Here you would write to your database.
// Example with entity framework:
using (var ctx = new YourDatabaseContext())
{
ctx.Something.Add(/**/);
ctx.SaveChanges();
}
}
}
}
然后将过滤器应用于作业方法:
namespace myAPI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start(
{
System.Diagnostics.Debug.WriteLine("Recurring job will be set up.");
RecurringJob.AddOrUpdate("some-id", () => MyJob(), "*/2 * * * 1-5");
}
[LogCompletion]
public static void MyJob()
{
System.Diagnostics.Debug.WriteLine("Job instance started at " + DateTime.Now)
}
}
}
文档:https://docs.hangfire.io/en/latest/extensibility/using-job-filters.html
实际问题是一个非常微不足道的问题,缺少实际后台服务器的初始化BackgroundJobServer();
。这里是完整的功能代码:
namespace myAPI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
string connString = ConfigurationManager.ConnectionStrings["myContext"].ToString();
Hangfire.GlobalConfiguration.Configuration.UseConsole();
Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage(connString,
new SqlServerStorageOptions {
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
});
var bgndJS = new BackgroundJobServer(); // <--- this is essential!
RecurringJob.AddOrUpdate("myRecurringJob", () => HangfireRecurringJob(), "*/2 * * * 1-5");
System.Diagnostics.Debug.WriteLine("---> RecurringJob 'myHangfireJob' initated.");
}
public void HangfireRecurringJob() {
System.Diagnostics.Debug.WriteLine("---> HangfireRecurringJob() executed at" + DateTime.Now);
Console.Beep(); // <-- I was really happy to hear the beep
}
}
}
我已经为我的 ASP.NET 项目设置 hangfire 成功,即在我的数据库中创建了 11 个 Hangfire 表。我在项目 Global.asax
的 Application_Start()
中尝试了以下命令:
namespace myAPI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start(
{
System.Diagnostics.Debug.WriteLine("Recurring job will be set up.");
RecurringJob.AddOrUpdate(
"some-id",
() => System.Diagnostics.Debug.WriteLine("Job instance started at " +
DateTime.Now)),
"*/2 * * * 1-5");
}
}
}
遗憾的是,在 Visual Studio 的 window Output > Debug 中,我只看到 Reccuring job will be set up.
,此后什么也没有。但是,SELECT * FROM [myContext].[HangFire].[Set]
显示我
Key Score Value ExpireAt
recurring-jobs 1579116240 some-id NULL
到目前为止一切顺利,这意味着作业确实设置好了。
但是 如何在每次执行 RecurringJob 时在我的数据库 中记录 ? 我是否正确地假设 Hangfire 可以不是开箱即用,我必须自己在箭头功能中记录它吗?还是有更优雅的方式?
旁边的问题:为什么我在的重复工作中看不到System.Diagnostics.Debug.WriteLine
的任何输出?
参考资料
- Hangfire doesn't create tables in IIS
- Official hangfire.io docu on recurrent tasks
因此 cron 已设置为启动 At every 2nd minute on every day-of-week from Monday through Friday。我假设您正在等待作业执行并且它是在正确的 window 时间。
我在网上找到的大部分参考资料都表明你可以做到。
RecurringJob.AddOrUpdate(() => Console.WriteLine("This job will execute once in every minute"), Cron.Minutely);
也许你需要把点排列得更好一点才能写入 vs 控制台。
还有一个管理门户,可以对其进行配置以查看什么是开始 运行 以及何时开始。
我有以下设置。 Global.asax.cs
protected void Application_Start()
{
HangfireJobsConfig.Register();
}
public class HangfireJobsConfig
{
public static void Register()
{
if (App1Config.RunHangfireService)
{
JobStorage.Current = new SqlServerStorage(App1Config.DefaultConnectionStringName.Split('=').Last());
GlobalConfiguration.Configuration.UseConsole();
RecurringJob.AddOrUpdate("RunJob1", () => RunJob1(null), Cron.MinuteInterval(App1Config.RunJob1Interval));
RecurringJob.AddOrUpdate("RunJob2", () => RunJob2(null), Cron.MinuteInterval(App1Config.RunJob2Interval));
}
}
[AutomaticRetry(Attempts = 0, Order = 1)]
public static void RunJob1(PerformContext context)
{
//dostuff
}
[AutomaticRetry(Attempts = 0, Order = 2)]
public static void RunJob2(PerformContext context)
{
//do stuff
}
}
Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
ConfigureHangFire(app);
}
public void ConfigureHangFire(IAppBuilder app)
{
if (App1Config.RunHangfireService)
{
GlobalConfiguration.Configuration.UseSqlServerStorage(
AppiConfig.DefaultConnectionStringName.Split('=').Last());
GlobalConfiguration.Configuration.UseConsole();
app.UseHangfireServer();
var options = new DashboardOptions
{
AuthorizationFilters = new[]
{
new AuthorizationFilter { Roles = "Inventory" }
}
};
app.UseHangfireDashboard("/hangfire", options);
}
}
}
您可以开箱即用 SeriLog with Hangfire。 Serilog 带有不同的接收器,例如Serilog.Sinks.MSSqlServer
。您可以在 startup.cs
:
using Serilog;
using Serilog.Sinks.MSSqlServer;
Log.Logger = new LoggerConfiguration()
.WriteTo
.MSSqlServer(
connectionString: hangfireConnectionString,
tableName: "Logs",
autoCreateSqlTable: true
).CreateLogger();
// will display any issues with Serilog config. comment out in prod.
Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));
GlobalConfiguration.Configuration
.UseSqlServerStorage(hangfireConnectionString)
.UseSerilogLogProvider();
安排工作后,您可以使用
记录它Log.Information(string.Format("Hanfire Job Scheduled at {0}", DateTime.Now));
Hangfire 包含 job filters 的概念(类似于 ASP.NET MVC 的 Action Filters)。对于您的用例,您将定义一个写入数据库的案例(根据您的需要进行调整):
using Hangfire.Common;
using Hangfire.Server;
class LogCompletionAttribute : JobFilterAttribute, IServerFilter
{
public void OnPerforming(PerformingContext filterContext)
{
// Code here if you care when the execution **has begun**
}
public void OnPerformed(PerformedContext context)
{
// Check that the job completed successfully
if (!context.Canceled && context.Exception != null)
{
// Here you would write to your database.
// Example with entity framework:
using (var ctx = new YourDatabaseContext())
{
ctx.Something.Add(/**/);
ctx.SaveChanges();
}
}
}
}
然后将过滤器应用于作业方法:
namespace myAPI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start(
{
System.Diagnostics.Debug.WriteLine("Recurring job will be set up.");
RecurringJob.AddOrUpdate("some-id", () => MyJob(), "*/2 * * * 1-5");
}
[LogCompletion]
public static void MyJob()
{
System.Diagnostics.Debug.WriteLine("Job instance started at " + DateTime.Now)
}
}
}
文档:https://docs.hangfire.io/en/latest/extensibility/using-job-filters.html
实际问题是一个非常微不足道的问题,缺少实际后台服务器的初始化BackgroundJobServer();
。这里是完整的功能代码:
namespace myAPI
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
string connString = ConfigurationManager.ConnectionStrings["myContext"].ToString();
Hangfire.GlobalConfiguration.Configuration.UseConsole();
Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage(connString,
new SqlServerStorageOptions {
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
UsePageLocksOnDequeue = true,
DisableGlobalLocks = true
});
var bgndJS = new BackgroundJobServer(); // <--- this is essential!
RecurringJob.AddOrUpdate("myRecurringJob", () => HangfireRecurringJob(), "*/2 * * * 1-5");
System.Diagnostics.Debug.WriteLine("---> RecurringJob 'myHangfireJob' initated.");
}
public void HangfireRecurringJob() {
System.Diagnostics.Debug.WriteLine("---> HangfireRecurringJob() executed at" + DateTime.Now);
Console.Beep(); // <-- I was really happy to hear the beep
}
}
}