Windows Service- Can it run two separate tasks scheduled at different intervals - c#

I have written a Windows Service which triggers email ONCE in a WEEK at specific time. The service runs perfectly fine. Code is shown below:
protected override void OnStart(string[] args)
{
this.Log("Simple Service Started");
this.ScheduleService();
}
protected override void OnStop()
{
this.Log("Simple Service Stopped");
this.Schedular.Dispose();
}
private Timer Schedular;
public void ScheduleService()
{
try
{
Schedular = new Timer(new TimerCallback(SchedularCallback));
// Code that schedules the Callback
}
}
private void SchedularCallback(object e)
{
try
{
// Scheduled Job code
}
}
Now I have another similar requirement where I have to trigger another email, but its schedule has to be ONCE in 2 WEEKS. Is there a way this job can be accommodated in the same service, or I have to write another service?

I once did a similar design in one of my projects.
Try having a base abstract "ScheduledTask" class that defines your timing behavior, and have it used by inherited tasks classes.
Here is what I did for timers, I think there's only little work to change it to a Scheduler.
internal abstract class TaskBase
{
/// <summary>
/// Task timer
/// </summary>
private readonly Timer _timer;
/// <summary>
/// Set refresh time
/// </summary>
protected int TimeRefreshSec { get; private set; }
/// <summary>
/// Loop of timePassed
/// </summary>
protected int TimePassed { get; private set; }
protected TaskBase(double refreshInterval)
{
TimeRefreshSec = (int) refreshInterval / 1000;
TimePassed = 0;
_timer = new Timer(refreshInterval) { AutoReset = true };
_timer.Elapsed += Tick;
}
private void Tick(object sender, ElapsedEventArgs e)
{
TimePassed += TimeRefreshSec;
Tick();
}
public void Start()
{
ResetTimer();
// Run the task once when starting instead of waiting for a full interval.
Tick();
OnStart();
}
public void Stop()
{
if (_timer.Enabled)
{
_timer.Stop();
OnStop();
}
}
protected virtual void ResetTimer()
{
TimePassed = 0;
if (_timer.Enabled) _timer.Stop();
_timer.Start();
}
/// <summary>
/// Implement here a specific behavior when task is stopped.
/// </summary>
protected abstract void OnStop();
/// <summary>
/// Implement here a specific behavior when task is started.
/// </summary>
protected abstract void OnStart();
/// <summary>
/// This method is executed each time the task's timer has reached the interval specified in the constructor.
/// Time counters are automatically updated.
/// </summary>
protected abstract void Tick();
}
and for the service :
public partial class MyService : ServiceBase
{
private readonly List<TaskBase> _tasks;
public MyService()
{
InitializeComponent();
// Add in this list the tasks to run periodically.
// Tasks frequencies are set in the corresponding classes.
_tasks = new List<TaskBase>
{
new InheritingTask(),
new OherInheritingTask()
};
}
protected override void OnStart(string[] args)
{
try
{
_tasks.ForEach(t => t.Start());
}
catch (Exception ex)
{
Stop();
}
}
protected override void OnStop()
{
_tasks.ForEach(t => t.Stop());
}
}
EDIT:
The code for a class inheriting TaskBase:
class InheritingTask: TaskBase
{
public InheritingTask()
: base(Settings.Default.InheritingTaskInterval) // In milliseconds
{
//TODO: Custom initialization here
}
protected override void Tick()
{
//TODO: Task logic here
}
protected override void OnStart()
{ }
protected override void OnStop()
{ }
protected override void ResetTimer()
{
//TODO: Custom reset logic here
base.ResetTimer();
}
}

You could easily make a 2nd Schedular that is started in ScheduleService that is set to go off in two weeks however a Timer that fires once a week or two is a horrible way to do this, if the computer reboots you loose your timer and the email you where waiting on will not get sent.
You need a database of some kind to store when the next event should fire to survive restarts of your program, use a library that stores and does the scheduling for you like Hangfire.

Yes, you can achieve this using multithreading, for example via Tasks or Backgroundworkers. With this you can start each timer on a different thread which executes your operation when the timer ticks. It would also be advisable to separate timer and execution on different threads - for example Backgroundworkers for Timer 1 and 2 and Backgroundworkers for Execution 1 and 2.

Related

VS 2015 C# - ElapsedEventHandler not firing in Service

I have developed my first C# Service in VS 2015, but I cannot get my ElapsedEventHandler method to fire. I have the following code:
using System;
using System.ServiceProcess;
using System.Timers;
namespace UpdateEnvironmentService
{
public partial class Scheduler : ServiceBase
{
private Timer timer = null;
public Scheduler()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer = new Timer();
this.timer.Interval = Convert.ToDouble(1000); //timer intraval in milliseconds
this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.UpdateData);
timer.Enabled = true;
Library.WriteLog("Data Updater Started ");
}
private void UpdateData(object sender, EventArgs e)
{
Library.WriteLog("Got to update Data ");
}
protected override void OnStop()
{
timer.Enabled = false;
timer = null;
Library.WriteLog("Data Updater Stopped ");
}
}
}
The line Data Updater Started gets printed to my log file, but I never end up seeing Got to update Data or even Data Updater Stopped. It seems my ElapsedEventHandler is never firing. Anybody have any idea why?
I would refer you to the documentation on MSDN for the System.Timers.Timer class.
Most examples and usage of the timer, tends to avoid setting Enabled directly and instead relies on the Start and Stop methods.
On a side-note, I would recommend that in the age of Task, that you approach the problem in a different way:
namespace UpdateEnvironmentService
{
public partial class Scheduler : ServiceBase
{
private readonly CancellationTokenSource _tcs;
public Scheduler()
{
InitializeComponent();
_tcs = new CancellationTokenSource();
}
protected override void OnStart(string[] args)
{
Library.WriteLog("Data Updater Started ");
Task.Factory.StartNew(Runner, _tcs.Token);
}
private async void Runner()
{
Library.WriteLog("In runner");
var delay = TimeSpan.FromSeconds(1);
while(!_tcs.IsCancellationRequested)
{
Library.WriteLog("Waiting...");
await Task.Delay(delay, _tcs.Token);
UpdateData();
}
Library.WriteLog("Cancellation requested; exiting runner");
}
private void UpdateData()
{
Library.WriteLog("Got to update Data ");
}
protected override void OnStop()
{
_tcs.Cancel();
Library.WriteLog("Data Updater Stopped ");
}
}
}
This approach removes the need for a timer, and instead introduces asynchrony from the task, allowing the threadpool to manage the delay; it also has the benefit of introducing nicer cancellation control, which means it can even be cancelled while it's waiting for the delay!

Abstract function and timers

I am pretty new to inheritance. Trying to implement a base class with a static timer. This timer will call an abstract function every time the time has elapsed. The reason is that two classes that inhereting from the base class will have a synchronized timers. Here is the code
Base class:
public abstract class UIControllers
{
public enum IndicatorColors
{
Green,
Red,
Yellow,
Blue
}
private static Timer UITimer;
public UIControllers()
{
EnableUITimer();
}
private int intervalInMillis = 500;
/// <summary>
/// Enables the timer responsible for UI effect in the GUI.
/// </summary>
private void EnableUITimer()
{
if (UITimer != null)
{
return;
}
UITimer = new Timer();
UITimer.Interval = intervalInMillis;
UITimer.Elapsed += UITimer_Elapsed;
UITimer.Start();
}
private void UITimer_Elapsed(object sender, ElapsedEventArgs e)
{
TimeElapsed();
}
/// <summary>
/// The function is being called when the time interval ellapsed
/// </summary>
protected abstract void TimeElapsed();
...
Derived class:
protected override void TimeElapsed()
{
....
}
It only works for one of my two classes that inheriting from the base class (whichever class was instantiated first it works for it).
Thanks
In EnableUITimer(), you wave off if the static instance has been created, so the only subclass instance that ever gets to give UITimer an event handler is the one that creates it -- the first one, as you noticed. The event handler is an instance method, a delegate.
Instead, do this:
private void EnableUITimer()
{
if (UITimer != null)
{
// If it already exists, give it a handler from this instance.
// Every instance that wants to be notified has to provide its own
// event handler.
UITimer.Elapsed += UITimer_Elapsed;
return;
}
UITimer = new Timer();
UITimer.Interval = intervalInMillis;
UITimer.Elapsed += UITimer_Elapsed;
UITimer.Start();
}
This section of code gets run 2x (once for each object instance)
public UIControllers()
{
EnableUITimer();
}
UITimer is static and null on first execution so ALL of EnableUITimers executes on the FIRST instance. With the second instance UITimer != null is true so EnableUITimer returns without creating the timer and wiring up UITImer_Elasped.
private void EnableUITimer()
{
if (UITimer != null)
{
return; // Exits on second instance
}
What you probably want to do is skip creating the timer if it is already instanced, but still wire up to the Elapsed event
private void EnableUITimer()
{
if (UITimer == null)
{
UITimer = new Timer();
UITimer.Interval = intervalInMillis;
UITimer.Start();
}
UITimer.Elapsed += UITimer_Elapsed;
}

Why is my System.Threading.Task.ContinueWith firing at the wrong time

I am trying to handle exceptions from a System.Threading.Tasks.Task
I haven't used these before, and seem to be misunderstanding how the ContinueWith works; thus my ContinueWith is firing at the wrong time.
Given the following; workers is just a list of my long running processes.
......
workers.Add(new Workers.Tests.TestWorker1());
workers.Add(new Workers.Tests.TestWorker2());
// Start all the workers.
workers.ForEach(worker =>
{
// worker.Start schedules a timer and calls DoWork in the worker
System.Threading.Tasks.Task task = new System.Threading.Tasks.Task(worker.Start);
task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
})
.....
My handler method is
private void ExceptionHandler(System.Threading.Tasks.Task arg1, object arg2)
{
DebugLogger.Write("uh oh.. it died");
}
My TestWorker's are:
class TestWorker1 : Worker
{
int count = 1;
public override void DoWork(object timerState)
{
DebugLogger.Write(string.Format("{0} ran {1} times", workerName, count));
count++;
ScheduleTimer();
}
}
And
class TestWorker2 : Worker
{
int count = 1;
public override void DoWork(object timerState)
{
DebugLogger.Write(string.Format("{0} ran {1} times", workerName, count));
count++;
if (count == 3)
throw new Exception("I'm going to die....");
ScheduleTimer();
}
}
ScheduleTimer() simply sets an interval for DoWork to be run
What happens...
When I debug, all tasks are created and started. As soon as theDoWork has called ScheduleTimer() for the first time, my ExceptionHandler is hit; as shown in this screenshot - this happens for both workers.
When the exception is hit in TestWorker2 the debugger will not move on from there - in that i press continue, hoping to hit my ExceptionHandler, and the debugger just keeps throwing the exception.
What I am hoping to achieve
I would like my ExceptionHandler to only fire when an exception within the running tasks is thrown. I'm finding the only time i get into my ExceptionHandler is when it's run, and my actual exception just keeps looping.
What am i missing?
Per comment, here is the code for the main Worker
public abstract class Worker : IDisposable
{
internal string workerName;
internal Timer scheduler;
internal DateTime scheduledTime;
public Worker()
{
string t = this.GetType().ToString();
workerName = t.Substring(t.LastIndexOf(".") + 1).AddSpacesBeforeUppercase(true).Trim();
}
/// <summary>
/// Set to true when the worker is performing its task, false when its complete
/// </summary>
public bool IsCurrentlyProcessing { get; set; }
public void Start()
{
DebugLogger.Write(workerName + " Started");
ScheduleTimer();
}
/// <summary>
/// default functionality for setting up the timer.
/// Typically, the timer will fire in 60 second intervals
/// Override this method in child classes for different functionality
/// </summary>
public virtual void ScheduleTimer()
{
scheduler = new Timer(new TimerCallback(DoWork));
int interval = 60;
int.TryParse(ConfigurationManager.AppSettings[string.Format("{0}{1}", workerName.Replace(" ", ""), "Interval")], out interval);
scheduledTime = DateTime.Now.AddSeconds(interval);
if (DateTime.Now > scheduledTime)
scheduledTime = scheduledTime.AddSeconds(interval);
int dueTime = Convert.ToInt32(scheduledTime.Subtract(DateTime.Now).TotalMilliseconds);
scheduler.Change(dueTime, Timeout.Infinite);
}
public abstract void DoWork(object timerState);
public void Stop()
{
// kill stuff
if (scheduler != null)
scheduler.Dispose();
DebugLogger.Write(workerName + " stop");
this.Dispose();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
if (disposing)
{
// any specific cleanup
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
From your screenshot it appears that arg2 is your TaskContinuationOptions.OnlyOnFaulted object, that is the biggest clue of what is going wrong. Because you passed in a Action<Task, Object> it is using the Task.ContinueWith Method (Action<Task, Object>, Object) overload of ContinueWith, this is causing your continuation options to be passed in as the state parameter.
Either change ExceptionHandler to
private void ExceptionHandler(System.Threading.Tasks.Task arg1)
{
DebugLogger.Write("uh oh.. it died");
}
so you will use the Task.ContinueWith(Action<Task>, TaskContinuationOptions) overload, or you can change your call to
task.ContinueWith(ExceptionHandler, null, TaskContinuationOptions.OnlyOnFaulted);
so that you will start using the Task.ContinueWith(Action<Task, Object>, Object, TaskContinuationOptions) overload.
Might be caused by your logging component not supporting multiple concurrent writes.
If it's possible for you, I'd suggest you refactor the code to the async/await pattern, it will be much more readable.
Let's say you create a list of all the tasks you want to run:
List<Task> tasks = new List<Task>();
workers.ForEach(worker => tasks.Add(Task.Run(() => worker.Start())));
and then use await on the list surrounded by a try catch block:
try
{
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
DebugLogger.Write("uh oh.. it died");
}
Also, make sure you are not doing any Thread.Wait(xxx) calls (or any other Thread.XXX calls for that matter) inside ScheduleTimer(), because tasks and threads don't play nice together.
Hope it helps!

Error 1053 service didnot respond to start or control request

I am learning window service from msdn link :
http://msdn.microsoft.com/en-us/library/zt39148a(v=vs.110).aspx
I have properly created , install first Time ....when I try to start it from Service.msc ..it is throwing Error :
Error 1053 service didnot respond to start or control request
this is my Code :
public partial class ASMSService : ServiceBase
{
private Timer myTimer;
TimeSpan setTime;
private DateTime previousDate;
private DateTime todaysDate;
public ASMSService()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
protected override void OnStart(string[] args)
{
myTimer = new System.Threading.Timer(new TimerCallback(TimerAction1));
SetTimer(11, 07, 00);
}
protected override void OnStop()
{
}
private void SetTimer(int hours, int minutes, int seconds)
{
todaysDate = DateTime.Today;
previousDate = todaysDate.AddDays(-1);
setTime = todaysDate.AddHours(hours).AddMinutes(minutes).AddSeconds(seconds).TimeOfDay; ;
}
private void TimerAction1(object e)
{
//some Code
}
}
this is design Code
partial class ASMSService
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.eventLog1 = new System.Diagnostics.EventLog();
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
//
// ASMSService
//
this.ServiceName = "ASMSService";
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();
}
#endregion
private System.Diagnostics.EventLog eventLog1;
}
this is Program class:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new ASMSService()
};
ServiceBase.Run(ServicesToRun);
}
}
I have read similar posts on this ..Some posts suggest to install microsoft Patch ..Other suggest the object created should be disposed properly ..I also tried to do that in Onstop method..But it is not working ..Some posts suggest that ServiceBase.Run() method should be called in Main() method ...it is also present in My code
Please Suggest
I can see one great problem with the ASMSService's timer:
It is created :
myTimer = new System.Threading.Timer(new TimerCallback(TimerAction1));
But it is never started:
private void SetTimer(int hours, int minutes, int seconds)
{
todaysDate = DateTime.Today;
previousDate = todaysDate.AddDays(-1);
setTime = todaysDate.AddHours(hours).AddMinutes(minutes).AddSeconds(seconds).TimeOfDay; ;
// You have set the setTime field, otherwise the timer will still have the infinite dueTime and interval - it is not running at all
// You should call SetChange method to start it.
this.mytimer.SetChange(0, (Int64)setTime.ToMilliseconds());
}
SetChange method is required to start the timer if you use the simplest constructor
You may also want to read the following links, they are dealing with similar situations and provide few insights to consider:
Windows service with timer
System.Threading.Timer Not Starting?

Not getting OnStart event log entry in Windows Service

I have the following code for a windows service project. I have successfully built it and installed it. When I start it I get an event started in the event log. However, I never get the event for "In Onstart" any idea why this is going on?
namespace ADServiceCarlos
{
public partial class ADServiceCarlos : ServiceBase
{
public ADServiceCarlos()
{
InitializeComponent();
this.AutoLog = true;
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource","MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart");
}
protected override void OnStop()
{
}
}
}
OK, so this may solve your problem. It's hard to tell exactly without being able to see all your code, but read this - more specifically the "caution" part.
Do not use the constructor to perform processing that should be in
OnStart. Use OnStart to handle all initialization of your service. The
constructor is called when the application's executable runs, not when
the service runs. The executable runs before OnStart. When you
continue, for example, the constructor is not called again because the
SCM already holds the object in memory. If OnStop releases resources
allocated in the constructor rather than in OnStart, the needed
resources would not be created again the second time the service is
called.
So everything you are doing to initialise the event log in your constructor should be moved to the OnStart event. This will ensure it is create properly each time the service start, which means you should be able to log your OnStart event correctly (providing you do it after initialisation)
Based on what #musefan posted, here is an example. I had to move everything out of the constructor completely.
public class ServiceMain : System.ServiceProcess.ServiceBase
{
public const string SERVICE_NAME = "ServiceName";
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public ServiceMain()
{
// This call is required by the Windows.Forms Component Designer.
InitializeComponent();
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.ServiceName = SERVICE_NAME;
this.CanPauseAndContinue = true;
}
static void Main()
{
//Log all unhandled exceptions
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new ServiceMain() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
components.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Set things in motion so your service can do its work.
/// </summary>
protected override void OnStart(string[] args)
{
//Do your stuff here
}
static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e)
{
Environment.Exit(1);
}
}

Categories