长时间运行的Quartz作业+ Topshelf-如果作业多次失败,则重新启动服务

时间:2020-06-08 10:11:30

标签: c# service quartz.net topshelf

我有一系列与Quartz + TopShelf实现中的作业相关的触发器。该作业需要长时间运行,某些触发器需要运行约2个小时。

作业的热点是使用Excel Automation处理.xls文件的作业。这是有时由于各种错误(例如此The remote procedure call failed. (Exception from HRESULT: 0x800706BE))服务挂起的地方。

我的问题是:

  1. 当遇到与Excel Automation相关的任何错误(请参阅“失败部件代码”)时,如何指示该服务执行受到威胁,我需要它重新启动自身?

  2. 是否可以确保首先由GC正确收集了所有Excel对象?

  3. 如果我设法重新启动该服务,如何通知Quartz正在运行的作业已停止并且需要恢复/重新执行其步骤?

服务部分:

using System;

internal static partial class Main
{
    public static void Main()
    {
        var rc = HostFactory.Run(x =>
        {
            x.Service<ScheduleService>(ServiceConfiguratorCallback);
            x.RunAsLocalSystem();
            Log.Logger = new LoggerConfiguration().MinimumLevel.Information().WriteTo.Console().WriteTo.File($@"{AppDomain.CurrentDomain.BaseDirectory}logs\\log.txt", rollingInterval: RollingInterval.Day).CreateLogger();
            x.UseSerilog(Log.Logger);
            x.SetDescription("Test service");
            x.SetDisplayName("Test service");
            x.SetServiceName("Test service");
        });
        var exitCode = Int(Convert.ChangeType(rc, rc.GetTypeCode()));
        Environment.ExitCode = exitCode;
    }

    private static void ServiceConfiguratorCallback(ServiceConfigurator s)
    {
        s.ConstructUsing(name => new ScheduleService());
        s.WhenStarted(tc => tc.Start());
        s.WhenStopped(tc => tc.Stop());
    }
}

执行部分:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

[PersistJobDataAfterExecution]
[DisallowConcurrentExecution]
public partial class SendEmailQlik : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        try
        {
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
            string appPath = AppDomain.CurrentDomain.BaseDirectory;
            string configpath = appPath + @"\Config.ini";
            IniData configdata = excelDownload.ReadIniFile(configpath);
            var mod_rulare = configdata["GENERAL"]("MODE");
            string numejob = context.JobDetail.Key.Name;
            string lastRun = context.PreviousFireTimeUtc?.DateTime.ToString() ?? string.Empty;
            Log.Information("Psst! Trigger-ul {triggername} s-a activat! Ultima oara am rulat la: {lastRun}", context.Trigger.Key.Name, lastRun);
            Log.Information("Se executa job-urile asociate trigger-ului {0}!", context.Trigger.Key.Name);
            if (mod_rulare.ToLower == "all")
            {
                Log.Information("Processing image files...");
                List<string> images = Utils.QlikExport(context);
                Log.Information("Processing xls files...");
                var r = Utils.GetContextXlsv2(context);
                r.Wait();
                List<string> xls = r.Result;
                Utils.SendEmails(images, xls, context);
            }
            else if (mod_rulare.ToLower == "rpt")
            {
                Log.Warning("Mod rulare is {0}", mod_rulare);
                Log.Information("Processing xls files...");
                var r = Utils.GetContextXlsv2(context);
                r.Wait();
                List<string> xls = r.Result;
            }
            else if (mod_rulare.ToLower == "img")
            {
                Log.Warning("Mod rulare is {0}", mod_rulare);
                Log.Information("Processing image files...");
                List<string> images = Utils.QlikExport(context);
            }
            else
            {
                Log.Error("Mode {0} is not recognized. Please set a valid run mode...", mod_rulare);
            }

            Log.Information("Waiting next schedule...");
            return Task.CompletedTask;
        }
        catch (Exception ex)
        {
            var jee = new JobExecutionException(ex);
            Log.Error("Error raised is: {0}", ex.Message);
            jee.RefireImmediately = true;
        }

        return default;
    }
} 

失败的部分:

 try
    {
        Log.Information("Instantiating xlApp for {agent}...", agent);
        object oMissing = Missing.Value;
        var exWbk = exApp.Workbooks.Open(filepath, oMissing, false, oMissing, oMissing, oMissing, true, oMissing, oMissing, true, oMissing, oMissing, oMissing, oMissing, oMissing);
        try
        {
            System.Threading.Thread.Sleep(200);
            Worksheet summary_wksheet = exWbk.Sheets("Summary");
            summary_wksheet.Activate();
            summary_wksheet.Move(Before: exWbk.Worksheets("Sheet1"));
            Log.Information("Refreshing data...");
            exWbk.Sheets("Summary").PivotTables("PivotTable1").PivotCache.Refresh();
            exWbk.RefreshAll();
            exApp.Calculate();
            exWbk.Save();
            exWbk.Close(0);
            exApp.Quit();
        }
        catch (COMException e)
        {
            if ((e.ErrorCode & 0xFFFF) == 0x10A)
            {
                System.Threading.Thread.Sleep(10000);
                exWbk.Close(0);
                exApp.Quit();
            }
            else
            {
                System.Threading.Thread.Sleep(10000);
                exWbk.Close(0);
                exApp.Quit();
                throw e;
            }
        }
    }
    catch (Exception e)
    {
        Log.Error("Error while opening Excel app for {0}: {1}", numeraport, e.Message);
        Log.Error("{0}|{1}|{2}|{4}|{3}", "EROARE", agent, "", e.Message, numeraport);
        System.Threading.Thread.Sleep(5000);
        Log.Error("Killing faulty Excel app process...");
        KillXLS();
        continue;
    }

0 个答案:

没有答案