For a project I'm converting an existing console to a Windows Service. The current console application runs a series of jobs consecutively.
The idea of the service is to run each of these jobs on a schedule. To do this we've created a windows service which does this using Hangfire.
The constructor
public BatchService(ILogger<BatchService> logger)
{
InitializeComponent();
GlobalConfiguration.Configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseColouredConsoleLogProvider()
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(Constants.ConnectionString.Peach,
new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true
})
.UseNLogLogProvider();
_logger = logger;
}
The methods used to load everything into Hangfire:
private void LoadConfigurationIntoHangfire()
{
// Loading the job configurationNo
var jobListing = Configuration.GetJobConfiguration().Where(job => job.JobType.Equals("CRON")).ToList();
// Debug
_logger.LogDebug($"LoadConfigurationIntoHangfire() - jobListing = {JsonConvert.SerializeObject(jobListing)}");
foreach (var job in jobListing)
{
// Information
_logger.LogInformation($"Added/updated job '{job.JobName}' with cron expression '{job.CronExpression}'.");
RecurringJob.AddOrUpdate<IDataProtectionJob>(x => x.ExecuteJob(job), job.CronExpression);
}
}
private void StopHangfire()
{
// Information
_logger.LogInformation($"Stopping Hangfire.");
_hangfireServer.SendStop();
_hangfireServer.WaitForShutdown(new TimeSpan(0, 0, 5));
_hangfireServer.Dispose();
// Information
_logger.LogInformation($"Hangfire stopped.");
}
private void StartHangfire()
{
// Information
_logger.LogInformation($"Starting Hangfire.");
_hangfireServer = new BackgroundJobServer();
LoadConfigurationIntoHangfire();
// Information
_logger.LogInformation($"Hangfire started.");
}
The OnStart event of the service:
protected override void OnStart(string[] args)
{
try
{
// Update the service state to Start Pending.
ServiceStatus serviceStatus = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = 100000
};
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
// Information
_logger.LogInformation("Starting Windows Service 'BatchService'");
SetPolling();
StartHangfire();
_logger.LogInformation("Windows Service 'BatchService' started");
// Update the service state to Running.
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}
catch (Exception e)
{
_logger.LogError($"Windows Service 'BatchService' failed to start ({e})");
throw;
}
}
The jobs are based on a interface IDataProtectionJob, which has an implementation,the implementation itself is beyond the scope (I think).
Now, the implementation builds and launches without problems, but... no tasks are executed. In the log files I found the following error messages:
2022-11-23 19:05:53.0881|DEBUG|Hangfire.Server.DelayedJobScheduler|2 scheduled job(s) processed by scheduler. 2022-11-23 19:05:53.1353|WARN|Hangfire.AutomaticRetryAttribute|Failed to process the job '17': an exception occurred. Retry attempt 5 of 10 will be performed in 00:05:36.|System.MissingMethodException: No parameterless constructor defined for this object. at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic) at System.Activator.CreateInstance(Type type) at Hangfire.JobActivator.ActivateJob(Type jobType) at Hangfire.JobActivator.SimpleJobActivatorScope.Resolve(Type type) at Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext context) at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass9_0.b__0() at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func1 continuation) at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass9_1.<PerformJobWithFilters>b__2() at Hangfire.Server.BackgroundJobPerformer.PerformJobWithFilters(PerformContext context, IEnumerable
1 filters) at Hangfire.Server.BackgroundJobPerformer.Perform(PerformContext context) at Hangfire.Server.Worker.PerformJob(BackgroundProcessContext context, IStorageConnection connection, String jobId) 2022-11-23 19:05:53.1383|WARN|Hangfire.AutomaticRetryAttribute|Failed to process the job '20': an exception occurred. Retry attempt 2 of 10 will be performed in 00:01:04.|System.MissingMethodException: Cannot create an instance of an interface. at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic) at System.Activator.CreateInstance(Type type) at Hangfire.JobActivator.ActivateJob(Type jobType) at Hangfire.JobActivator.SimpleJobActivatorScope.Resolve(Type type) at Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext context) at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass9_0.b__0() at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func1 continuation) at Hangfire.Server.BackgroundJobPerformer.<>c__DisplayClass9_1.<PerformJobWithFilters>b__2() at Hangfire.Server.BackgroundJobPerformer.PerformJobWithFilters(PerformContext context, IEnumerable
1 filters) at Hangfire.Server.BackgroundJobPerformer.Perform(PerformContext context) at Hangfire.Server.Worker.PerformJob(BackgroundProcessContext context, IStorageConnection connection, String jobId)
I googled the error message, found some explanation based on the way Hangfire resolves the dependencies of the methods you assign to it for execution.
I've played around a bit with, but to no avail. What can I try next?
OS: Windows Server 2016
.NET version: 4.6.1