I have created a Windows Service using Topshelf that is meant to run on a fixed schedule and continue running every day. I am able to install the service and when I start it, it will run correctly during that day.
The problem that I encounter is that at the end of each day, the service stops polling. It no longer writes out to the log to indicate that the service is running or that the timer is tracking. Windows still lists this service as running, with the option to either stop or restart. I can manually restart the service which will let the service run until the end of the day. However, once the day ends and a new day begins, the service no longer seems to be running.
I have made some attempts to modify the settings for this service with no success. Is there a configuration value that needs to be set in order to let the service keep running without the need for a manual restart every day?
This is the relevant code for program.cs:
namespace MyService
{
class Program
{
static void Main(string[] args)
{
{
HostFactory.Run(x =>
{
x.Service<ServiceManager>(s =>
{
s.ConstructUsing(FileProcess => new ServiceManager());
s.WhenStarted(FileProcess => FileProcess.Start());
s.WhenStopped(FileProcess => FileProcess.Stop());
});
x.StartAutomatically();
x.RunAsLocalSystem();
x.EnableServiceRecovery(recoverOption =>
{
recoverOption.RestartService(1);
recoverOption.RestartService(5);
recoverOption.TakeNoAction();
});
x.SetServiceName("MyService");
x.SetDisplayName("MyService v1.0");
x.SetDescription("This is the description for MyService.");
});
}
}
}
}
And the relevant code for ServiceManager.cs:
namespace MyService
{
public class ServiceManager
{
private readonly Timer _timer;
private static Logger logger = LogManager.GetCurrentClassLogger();
public ServiceManager()
{
logger.Info("Service manager start");
ConfigurationManager.RefreshSection("appSettings");
ConfigurationManager.RefreshSection("connectionStrings");
//Converts TimerInterval from app.config into minutes. Timer elapses every (TimerInterval) minutes.
Double timerInterval = (Convert.ToDouble(ConfigurationManager.AppSettings["TimerInterval"]) * 1000 * 60);
_timer = new Timer(timerInterval) { AutoReset = true };
_timer.Elapsed += TimerElapsed;
logger.Info("Service manager end");
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
TaskManager tm = new TaskManager();
tm.Run();
}
public void Start()
{
logger.Debug("Start service");
_timer.Start();
}
public void Stop()
{
logger.Debug("Stop service");
_timer.Stop();
}
}
}
Related
This question already has answers here:
Better way to constantly run function periodically in C#
(3 answers)
Closed 2 years ago.
Id like to build a windows Service in C#.
This service needs to be run periodically like every 10s.
Questions:
What is the difference between Timers.timer and Threading.timer?
How can I call CheckingThings with parameters?
If i run this code, it does invoke CheckingThings more than once every second like declared in here:
_timer = new Timer(new TimerCallback(CheckingThings), autoEvent, 5000, 1000);
Here is what i've got so far:
public partial class WindowsService1 : ServiceBase
{
// Logging
private static Serilog.Core.Logger _logEvent;
public WindowsService1()
{
InitializeComponent();
}
public void OnDebug() {
OnStart(null);
}
protected override void OnStart(string[] args)
{
//Logging
try {
_logEvent = new LoggerConfiguration()
.WriteTo.File(AppDomain.CurrentDomain.BaseDirectory + #"Logs\Logfile.txt", rollingInterval: RollingInterval.Month)
.CreateLogger();
}
catch (Exception e)
{
_logEvent.Error("The logging service is not working as expected: {errorMsg}", e);
}
try
{
// initializing some data here
var autoEvent = new AutoResetEvent(true);
while (true)
{
_timer = new Timer(new TimerCallback(CheckingThings), autoEvent, 5000, 1000);
}
}
catch (Exception e) {
_logEvent.Error("An error occured while initializing service: {0}", e);
}
}
private static void CheckingThings(object stateInfo)
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
//These things needs to run periodically every 10s
}
protected override void OnStop()
{
_logEvent.Information("Stopping Service ...");
}
}
Here's a skeleton for a service class that does something every minute, using a System.Timers.Timer:
public partial class XService : ServiceBase
{
private Timer _minute = new Timer(60000);
public XService()
{
InitializeComponent();
_minute.Elapsed += Minute_Elapsed;
}
//this is async because my 'stuff' is async
private async void Minute_Elapsed(object sender, ElapsedEventArgs e)
{
_minute.Stop();
try
{
//stuff
}
catch (Exception ex)
{
//log ?
}
finally
{
_minute.Start();
}
}
protected override void OnStart(string[] args)
{
_minute.Start(); //this or..
Minute_Elapsed(null, null); //..this, if you want to do the things as soon as the service starts (otherwise the first tick will be a minute after start is called
}
...
I typically stop my timers while I do my thing - no point starting a job that takes 10 minutes and then another one a minute later, hence the stop/try/finally/start pattern
Edit:
Here's the tail part of the class and how it's started/launched both in debug (inside visual studio) and in release (as an installed windows service):
//just an adapter method so we can call OnStart like the service manager does, in a debugging context
public void PubOnStop()
{
OnStop();
}
}// end of XService class
static void Main(string[] args)
{
#if DEBUG
new XService().PubStart(args);
Thread.Sleep(Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new XService()
};
ServiceBase.Run(ServicesToRun);
#endif
}
I have developed a Windows Service capable of running a few plugins. Due to its nature, when developing Windows Services, the Start and Stop methods should run and return as fast as possible. The Start method runs Start methods from all plugins, which also should not block the execution. In this example, both plugins instantiate a Threading.Timer, which run in background.
The execution order happens as follows. The arrows indicate what runs in a different thread:
-> MyService.Start -> pA.Start -> pb.Start -> return
\_> DoWork() \
\_> DoWork()
Since both DoWork() are running inside a Timer, if an Exception happens, I am unable to catch it. This could easily be avoided if I could modify PluginA and PluginB, but I can't.
Any suggestion on what I could do to avoid this issue? Thanks in advance.
The following code is an oversimplification of the real code:
public class MyService
{
private PluginA pA = new PluginA();
private PluginB pB = new PluginB();
// Windows Service runs Start when the service starts. It must return ASAP
public void Start()
{
// try..catch doesn't capture PluginB's exception
pA.Start();
pB.Start();
}
// Windows Service runs Stop when the service Stops. It must return ASAP
public void Stop()
{
pA.Stop();
pB.Stop();
}
}
// I have no control over how this is developed
public class PluginA
{
private Timer _timer;
public void Start()
{
_timer = new Timer(
(e) => DoWork(),
null,
TimeSpan.Zero,
TimeSpan.FromSeconds(10));
}
private void DoWork()
{
File.AppendAllText(
"C:/log.txt",
"hello" + Environment.NewLine);
}
public void Stop()
{
_timer.Change(Timeout.Infinite, 0);
}
}
// I have no control over how this is developed
public class PluginB
{
private Timer _timer;
public void Start()
{
_timer = new Timer(
(e) => DoWork(),
null,
TimeSpan.Zero,
TimeSpan.FromSeconds(10));
}
private void DoWork()
{
File.AppendAllText(
"C:/log.txt",
"Goodbye" + Environment.NewLine);
throw new Exception("Goodbye");
}
public void Stop()
{
_timer.Change(Timeout.Infinite, 0);
}
}
You can also use the AppDomain.UnhandledException Event.
Please note that you can't recover from such an exception.
I tried to deploy one service which works great in local to the production server. But on this server, the ElapsedEventHandler seems to never call my method Tick()
I have read other similar threads as
First Windows Service - timer seems not to tick
or
Timer tick event is not called in windows service
but i couldn't have any answer to my problem :/
I also tried to use _timer.Enabled=1 instead of _timer.Start (no incidence normally but still tried) and also tried to reinstall service a couple of times.
I use the Timer from Class System.Timers.
here is my code :
static void Main()
{
var servicesToRun = new ServiceBase[]
{
new SynchronizeEvents()
};
#if DEBUG
servicesToRun.LoadServices();
#else
ServiceBase.Run(servicesToRun);
#endif
}
and
public partial class SynchronizeEvents : ServiceBase
{
private readonly Logger _logger = LogManager.GetCurrentClassLogger();//Nlog
private Timer _timer;//From Class System.Timers
private readonly DbSetName _db = new DbSetName ();
private static readonly Dictionary<Employee, otherStuff> Subscriptions = new Dictionary<Employee, otherStuff>();
public SynchronizeEvents()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_logger.Trace("Service Start");
_timer = new Timer(5000) { AutoReset = false };//Same problem without AutoReset = false
_timer.Elapsed += Tick;
_timer.Start();
_logger.Trace("End OnStart");
}
protected override void OnShutdown()
{
_logger.Trace("OnShutdown");
_timer.Stop();
base.OnShutdown();
}
protected void Tick(object sender, ElapsedEventArgs elapsedEventArgs)
{
_logger.Trace("Tick");
_timer.Stop();
Compute();
_timer.Start();
}
protected override void OnStop()
{
_logger.Trace("OnStop");
}
Everything works great while on DebugMode and also on local computer in Release mode, but when i install it on production server the only logs i got are :
2014-09-08 16:35:57.1929 TRACE Service Start
2014-09-08 16:35:57.2085 TRACE End OnStart
i also got this when i stop the service...
2014-09-08 16:40:52.4072 TRACE End OnStop
Actually i got to apologize to Steve Wellens, he was right to ask about what Compute do.
The problem was related to Compute().
It had some code which required a DLL which was missing.
I don't know why _logger.Trace("Tick"); wasn't called and no Exception was triggered :/
I had to comment my program line per line to find out where the problem came from...
I have a windows service that I made for MY server...
I need to check every minute if there is some new info in my SQL Database.
So I made a windows service that create a Timer with interval of 1 minute.
But The windows service set the timer and ending the run.
It's goes like this:
Starting Service
Setting Timer with interval
Finishing and exiting Service <-- I want to keep it alive
As you can see the Service exit and I want the Windows service to run every minute without stopping....
I can see in the Event Viewer that there are the "Service started successfully." And the "Service stopped successfully."
What should I do?
P.S : I thought Timer should work with out exit... or may I wrong?
CODE:
Windows service:
static void Main(string[] args)
{
try
{
Utils.SetConfigFile();
var ServiceToRun = new TaoTimer();
ServiceToRun.Start();
}
catch (Exception ex)
{
EventLog.WriteEntry("Application", ex.ToString(), EventLogEntryType.Error);
}
}
TaoTimer:
public partial class TaoTimer : ServiceBase
{
List<TimerModel> timerList;
public TaoTimer()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
EventLog.WriteEntry("Started");
}
public void SetTimer(TimerModel timerModel)
{
int minute = 1000 * 60;
try
{
AlertTimer at = new AlertTimer(timerModel, minute);
at.Start();
}
catch
{
}
}
protected override void OnStop()
{
EventLog.WriteEntry("Stopped");
}
protected override void OnPause()
{
EventLog.WriteEntry("Paused");
}
protected override void OnContinue()
{
EventLog.WriteEntry("Continuing");
}
protected override void OnShutdown()
{
EventLog.WriteEntry("ShutDowned");
}
public void Start()
{
SetTimerList();
}
protected void SetTimerList()//Read Config from xml and start the timer
{
XElement root = XElement.Load(#"C:\TaoTimer\Data.xml");
timerList = new List<TimerModel>(from d in root.Descendants("Timer")
select new TimerModel(
d.Element("Id").Value.ToString(),
d.Element("Name").Value.ToString(),
d.Element("InterVal").Value.ToString(),
d.Element("TimeFormat").Value.ToString(),
d.Element("Day").Value.ToString(),
d.Element("TimeStamp").Value.ToString()));
timerList.ForEach(i => SetTimer(i));
}
}
AlertTimer:
public class AlertTimer
{
static System.Timers.Timer aTimer = new System.Timers.Timer();
public AlertTimer(TimerModel timerModel, int milliseconds)
{
aTimer.Elapsed += new ElapsedEventHandler((sender, e) => OnTimedEvent(sender, e, timerModel));
aTimer.Interval = milliseconds;
}
public void Start()
{
aTimer.Enabled = true;
}
public static void OnTimedEvent(object source, ElapsedEventArgs e, TimerModel timerModel)
{
getAbsenceContacts.Start();<-- NEVER GETS HERE....
}
}
You're not actually starting your service. You're calling a method named Start, which is not part of the Windows Service class hierarchy it's just a method you've defined. Your method runs and finishes, so the service exits.
Try this:
static void Main(string[] args)
{
try
{
Utils.SetConfigFile();
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new TaoTimer()
};
ServiceBase.Run(ServicesToRun);
}
catch (Exception ex)
{
EventLog.WriteEntry("Application", ex.ToString(), EventLogEntryType.Error);
}
}
public partial class TaoTimer : ServiceBase
{
...
protected override void OnStart(string[] args)
{
SetTimerList();
EventLog.WriteEntry("Started");
}
....
}
and remove the Start method from TaoTimer entirely.
You need to store your AlertTimer instances in something that will last the lifetime of the service (e.g. in a List<AlertTimer> declared as a field inside TaoTimer.
It's only really alluded to in the documentation for Timer that timer's, in and of themselves, don't prevent themselves from being garbage collected. The example says:
// Normally, the timer is declared at the class level,
// so that it stays in scope as long as it is needed.
// If the timer is declared in a long-running method,
// KeepAlive must be used to prevent the JIT compiler
// from allowing aggressive garbage collection to occur
// before the method ends. You can experiment with this
// by commenting out the class-level declaration and
// uncommenting the declaration below; then uncomment
// the GC.KeepAlive(aTimer) at the end of the method.
//System.Timers.Timer aTimer;
Now, whilst your timer's are declared at the class level inside of your AlertTimer class, there's nothing to stop the AlertTimer instances, themselves, from being collected. And the GC only keeps things alive that are transitively reachable. Once the AlertTimer instances are collectible, so are your Timer objects.
I have this simple windows service that is part of a browser game. What it does is check against database and if needed updates some rows. These actions takes about .5 to 1 second.
The data it reads is a date which tells if an item should be updated.
It works perfectly, however it is always around 25 seconds late. If I add an item to the queue, and that item is completed at 15:00:00, the service will update it at 15:00:25ish.
I've tried using threading.timer, a single thread and timers.timer and all works in the same way. I've also tried stopping the timer while the elapsed was running, although it takes less than a second so it should not be a problem.
I've also tried to attach the service to a debugger, and the same thing happens UNLESS I put a breakpoint. Then it happens as soon as it hits the breakpoint and i press f5 to continue.
Can anyone shed some light as to why the service seems to be behind? And a possible fix.
I was thinking I ran out of thread but I have a good 1000 left, so I'm kinda blank.
Please ask if you need more details, so I can provide.
I'm using .net 4.0 / C#
Threading.Thread
public partial class Service : ServiceBase
{
Thread thread;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
thread = new Thread(DoWork);
thread.Start();
}
private static void DoWork()
{
while (true)
{
//finish workingqueueitems
WorkingQueue.ProcessFinishedItems();
Thread.Sleep(1000);
}
}
protected override void OnStop()
{
thread.Abort();
}
}
Timers.Timer
public partial class Service : ServiceBase
{
System.Timers.Timer workingQueueTimer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
workingQueueTimer = new System.Timers.Timer();
workingQueueTimer.Elapsed += new ElapsedEventHandler(workingQueueTimer_Elapsed);
workingQueueTimer.Interval = 1000;
workingQueueTimer.Enabled = true;
}
void workingQueueTimer_Elapsed(object sender, ElapsedEventArgs e)
{
workingQueueTimer.Enabled = false;
DoWork();
workingQueueTimer.Enabled = true;
}
private static void DoWork()
{
//finish workingqueueitems
WorkingQueue.ProcessFinishedItems();
}
protected override void OnStop()
{
workingQueueTimer.Stop();
workingQueueTimer.Dispose();
}
}
The problem could be due to:
your DoWork() method takes 25 sec to complete
You are seeing the db data cached in someway or a transaction is delaying it
your method WorkingQueue.ProcessFinishedItems() is taking the wrong rows to update
if your service and db are in separeted machine they have a different time clock of 25 sec