【问题标题】:Logging the execution of a Hangfire RecurringJob in database?在数据库中记录 Hangfire RecurringJob 的执行?
【发布时间】:2020-01-16 09:39:17
【问题描述】:

我已经为我的 ASP.NET 项目成功设置了hangfire,即在我的数据库中创建了 11 个 Hangfire 表。我在我项目的Global.asaxApplication_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 的窗口中 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 的任何输出我的经常性工作中?

参考文献

【问题讨论】:

    标签: c# asp.net logging hangfire


    【解决方案1】:

    您可以直接使用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));
    

    【讨论】:

    • 感谢您的意见!知道为什么我的简单日志记录不起作用吗?
    • 我不太确定。我认为是因为您正在安排工作并且您等待的时间不够长?我认为您在周一至周五每 2 分钟安排一次。试试看这是否有效BackgroundJob.Enqueue( () => System.Diagnostics.Debug.WriteLine("Job executed at " +DateTime.Now + "."));
    • 您的hangfire 服务器是否在同一个应用程序中运行?还是只是仪表板?试试@JohnBabb 的建议。 GlobalConfiguration.Configuration.UseConsole();
    • 我不使用仪表板,我的 hangfire 服务器由我的 API 启动 - 我在帖子中添加了一些代码。我目前正在安装Hangfire.Console,所以你的提示很有帮助。
    【解决方案2】:

    Hangfire 包含job filters 的概念(类似于 ASP.NET MVC 的动作过滤器)。对于您的用例,您可以定义一个写入数据库的程序(根据您的需要进行调整):

    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

    【讨论】:

    • [LogCompletion] 属性应该在您作为作业调用的方法上,无论该方法位于哪个类中
    • 作业过滤器的具体用途是什么?有什么定义吗?您链接的文档有点稀疏。
    • 没错,他们的文档很小。将作业过滤器视为作业发生的各种操作的“事件侦听器” - 它被安排、执行、删除等。对于您的情况,您可以“侦听”执行事件并根据需要记录(例如您选择的数据库)。作业过滤器在每个作业的基础上应用 - 在您作为作业调用的方法上。你也可以将它们应用到一个类中,这只是一个将过滤器应用到该类中的每个方法的快捷方式。
    【解决方案3】:

    所以 cron 被设置为触发 At every 2nd minute on every day-of-week from Monday through Friday。我假设您正在等待作业执行并且它在正确的时间窗口中。

    我在网上找到的大多数参考资料都表明您可以做到。

    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);
                }
            }
        }
    

    【讨论】:

    • 感谢您的解释。我的主要问题不是初始设置,而是实际日志记录:换句话说:我希望每次执行作业时(在我的示例中为调试目的每 2 分钟一次),我的数据库中的日志条目。在生产环境中,这项工作应该每天(工作日)执行一次。
    【解决方案4】:

    实际问题是一个非常琐碎的问题,实际后台服务器的初始化缺少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
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-05-13
      相关资源
      最近更新 更多