I have a series of triggers associated to a job in a Quartz + TopShelf implementation. The job is long running, some triggers run for ~ 2 hrs.
The hot spot of the job is the job that uses Excel Automation to process .xls files. This is the point where, sometimes, due to various errors, eg this one The remote procedure call failed. (Exception from HRESULT: 0x800706BE)
, the service hangs.
My questions are:
How can I instruct the service, while I encounter any error related to Excel Automation ( see the Failing part code ), that the execution is compromised and I need it to restart itself?
Is there a way to make sure first that all of the Excel objects have been properly collected by the GC?
If I manage to restart the service, how can I inform Quartz that the job that was running was halted and it needs to resume / re-execute its steps?
Service part:
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());
}
}
Execute part:
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;
}
}
The failing part:
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;
}
User contributions licensed under CC BY-SA 3.0