After many moments of scratching my head and extreme annoyance with the MS Timer Bug.
Not only did it swallow exceptions, the timer did not raise the event! My service was hanging, which was particularly difficult because it also swallowed exceptions.
Now I did go down the route of half implementing with Threading.Timer
Don't use System.Windows.Forms.Timer because it won't work (this only makes sense).
Don't use System.Threading.Timer because it doesn't work, use System.Timers.Timer instead.
Don't use System.Timers.Timer because it doesn't work, use System.Threading.Timer instead.
Related question.
I really could not be bothered with the issues that came with these steps, as my aim was to focus on the business logic. So I made the decision to use Quartz.Net.
It made my life much easier and seems to work perfectly! 45-60 minutes worth of work.
Basic Setup:
1, Nuget > Quartz
2, New Folder(s) > QuartzComponents > Jobs and Schedule
3, Added OrderJob.cs
and OrderJobSchedule.cs
in respective folders
OrderJob.cs logic:
public sealed class OrderJob : IJob
{
public void Execute(IJobExecutionContext context)
{
var orderUoW = new OrderUoW();
orderUoW.Create();
}
}
Notice that it creates and instance of my UoW?!? logic that it would hit on each pass.
OrderJobSchedule.cs logic:
public sealed class OrderJobSchedule
{
public void Start()
{
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Start();
IJobDetail job = JobBuilder.Create<OrderJob>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithSimpleSchedule(a => a.WithIntervalInSeconds(15).RepeatForever())
.Build();
scheduler.ScheduleJob(job, trigger);
}
public void Stop()
{
IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
scheduler.Shutdown();
}
}
A lot of magic here, but to emphasis on:
JobBuilder.Create<OrderJob>().Build();
a.WithIntervalInSeconds(15).RepeatForever()
Now that's in place we need to add logic to the "guts" of the service:
public partial class QuayService : ServiceBase
{
OrderJobSchedule scheduler;
public QuayService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
scheduler = new OrderJobSchedule();
scheduler.Start();
SendEmail("(Shopify)Quay Service Started",
"(Shopify)Quay Service Successfuly Started");
}
catch (Exception ex)
{
ProcessException(ex, "Error starting (Shopify)Quay Service");
EventLog.WriteEntry("Error starting (Shopify)Quay service and timer..." + ex.Message);
}
}
protected override void OnStop()
{
try
{
if (scheduler != null)
{
scheduler.Stop();
}
SendEmail("(Shopify)Quay Service stopped",
"(Shopify)Quay Service Successfuly Stopped");
}
catch (Exception ex)
{
ProcessException(ex, "Error stopping (Shopify)Quay Service");
EventLog.WriteEntry("Error stopping (Shopify)Quay timer and service..." + ex.Message);
}
}
private void SendEmail(string subject, string body)
{
new Email().SendErrorEmail("Quay", subject, body);
}
private void ProcessException(Exception ex,
string customMessage)
{
var innerException = "";
if (ex.InnerException != null)
innerException = (!string.IsNullOrWhiteSpace(ex.InnerException.Message)) ? ex.InnerException.Message : "";
new Email().SendErrorEmail("Quay", customMessage,
ex.Message + " " + innerException);
}
}
Very easy to set up and solved my horrendous experience with Timers.Timer
Whilst I didn't fix the core issue, I came up with a solution and got a bug free working system in place.
Please note to future readers DO NOT USE System.Timers.Timer
unless you are prepared to add a "hack'ish" fix.