I have created a .NET Windows Service and installed the debug release from the bin/debug folder (yes I know this isn't a good approach, but I just want to be able to test it and attach debugger).
The service basically runs in an endless loop checking an FTP directory for files, processing them, sleeping for a minute and then looping.
When I attempt to start the service I get the following error
Error 1053: The service did not respond to the start or control request in a timely fashion
On further inspection the service is completing the first loop and then timing out during the first thread sleep. As such I'm somewhat confused as to how I should start the service. Is it my (lack of) understanding of threading that is causing this?
My start code is
protected override void OnStart(string[] args)
{
eventLog.WriteEntry("Service started");
ThreadStart ts = new ThreadStart(ProcessFiles);
workerThread = new Thread(ts);
workerThread.Start();
}
In the ProcessFiles function, once a loop has been completed I simply have
eventLog.WriteEntry("ProcessFiles Loop complete");
Thread.Sleep(new TimeSpan(0,1,0));
When I check the event logs the 'ProcessFiles Loop complete' log is there, but that is the last event before the service timesout and fails to start.
Can someone explain what I am doing wrong?
EDIT
The way I am handling the loop in my ProcessFiles function is as below
while (!this.serviceStopped)
{
// Do Stuff
eventLog.WriteEntry("ProcessFiles Loop complete");
Thread.Sleep(new TimeSpan(0,1,0));
}
Cheers
Stewart
When I check the event logs the 'ProcessFiles Loop complete' log is there...
You might be having a code for file processing that does not return until the service gets timeout. You are trying to perform some task after interval, you better use System.Timers.Timer or System.Windows.Forms.Timer instead of loop to repeatedly perform some task.
To test if it is loop problem to can restrict loop to single iteration with sleep statement and check if service gets started.
protected override void OnStart(string[] args)
{
aTimer = new System.Timers.Timer(10000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 60000;
aTimer.Enabled = true;
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
aTimer.Enabled = false;
// Put file processing code here.
aTimer.Enabled = true;
}
Doh. I just realised I had the following code in my Main Program method that I was using to be able to debug in VS. Obviously then when I installed the debug release it was putting an infinite timeout on the main thread. Removing the debug code fixed the issue.
#if DEBUG
AdvanceLinkService myService = new AdvanceLinkService();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new AdvanceLinkService()
};
ServiceBase.Run(ServicesToRun);
#endif
Related
In below program, What I am trying to achieve is when I press Ctrl+C or give SIGTERM then I want to make 'isEnable' false and let the while loop finish executing it's code one last time and exit the program gracefully.
I can achieve this only with CancelKeyPress because EventArgs passed on this handler has Cancel property and I just need to set it true. And, CancelKeyPress only handle Ctrl+C. But, I want same thing when I got SIGTERM signal.
Does anyone know is it possible to resuming the process after getting SIGTERM signal just like in CancelKeyPress?
Please let me know if you need more information to understand my question.
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
bool isEnable = true;
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
isEnable = false; // making while loop false
Console.WriteLine("Inside CancelKeyPress");
};
AppDomain.CurrentDomain.ProcessExit += (s, e) =>
{
isEnable = false; // making while loop false
Console.WriteLine("AppDomain ProcessExit!");
};
while (isEnable)
{
Console.WriteLine("first");
Thread.Sleep(3000);
Console.WriteLine("Second");
Thread.Sleep(3000);
Console.WriteLine("Third");
Thread.Sleep(3000);
Console.WriteLine("Fourth");
Thread.Sleep(3000);
}
Console.WriteLine("Gracefull Shotdown");
}
}
SIGTERM is a "polite" way of asking the program to terminate gracefully.
The program can then handle this is any way it wishes.
It can ignore it
It can shut down immediately
It can finish processing the current task, then gracefully
shutdown (disconnect from DB, close files etc).
It can wait as long as it wants and then shutdown.
(If running under Kubernetes then you can configure how long K8s will wait between sending a SIGTERM and a SIGKILL. So if your app needs 10 minutes to shut down then you can configure this and it is considered perfectly acceptable.)
In your code above, you are not "resuming processing" but are choosing to catch and handle this in your program by effectively ignoring the CTRL-C request.
So there is no reason why you can't do this also when receiving a SIGTERM on other platforms.
You might find this post helpful:
https://medium.com/#rainer_8955/gracefully-shutdown-c-apps-2e9711215f6d
I have a service which creates a FileSystemWatcher inside OnStart and I want the service to end only after a file is created
So I have this code
protected void OnStart()
{
try
{
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
watcher.Path = WatchPath;
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.Filter = "*.txt";
watcher.IncludeSubdirectories = false;
watcher.Changed += OnCreated;
watcher.EnableRaisingEvents = true;
logEvents.Write(MyLogClass.LogLevel.Info, "Watcher created");
}
}
catch (Exception ex)
{
logEvents.Write(MyLogClass.LogLevel.Info, ex.Message);
}
if (finished)
{
OnStop();
}
}
The bool "finished" is only set to true in the last line of OnCreated
private void OnCreated(object sender, FileSystemEventArgs e)
{
//Here I do all the stuff I need and then:
finished = true;
}
But even when OnCreated is not executed the service ends and I get:
"The program - has exited with code 0 (0x0)."
I've tried calling OnStop() in different parts of the code but the same thing happens anyways. I'd like the service to stay still until a given file is created and to start over when OnCreated is done, but I don't know what's wrong in this.
A FileSystemWatcher, by itself, isn't enough to keep a process running. When no events are being serviced, no threads are required, and even when one is required it'll be a background thread.
What a process needs to stay running is a foreground thread. It doesn't matter what that thread is doing, so long as at least one exists.
It doesn't look like you have any useful work for such a thread to do - but you need one. I suggest you create a thread that just waits for a ManualResetEvent to become set. You then use that, rather than your finished variable, to indicate when you want the service to shut down.
At that point, the foreground thread exits, no foreground threads are left, the process shuts down and the service becomes stopped.
Note that you have to create a new thread for this waiting work. The thread on which OnStart (and OnStop) is called doesn't "belong" to you. It's a thread that services the Service Control Manager, and you need to let it do that.
Your code is executing once and then ending.
You need a loop with a sleep timer around the main code to keep it alive. And in here embed your check for finished.
Edit:
As mentioned in the comments.
I missed that you were doing this in OnStart. The loop shouldn't be done here otherwise windows will think that you service failed to start. So you will also need to refactor this.
I have a windows service that archives files from a paticular folder. I want the program to run everday at a specific time. I can do that using the task scheduler. what I want to do is to schedule the task without actually assessing the windows task scheduler GUI. Maybe a batch script that schedules the program to run every day even when the system is on sleep or maybe something else i can do?
does anyone have an idea of how this thing can be implemented?
The solution is pretty basic . so the thing is that instead of using the task scheduler we are creating a scheduler itself in our code so there is a thread that will be created that will always be checking for the time that I want my actual code to run and once the current time is the time that I want the method to run it will trigger the main program(in the example the method I want to trigger is named ArchiveFile) .
so first in the OnStart I am setting a new timer and want it to fire 24x7,every hour.
then in the timer_elapse i want to check if the current time is the time I want my method to execute and if true it will call the method that I want to execute.(in this example I have set the time to be 9 pm or 21 hours)
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer();
timer.Interval = 36000; // that fires every hour
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); //calling the elapse event when the timer elapses
timer.AutoReset = true; // AutoReset is set to true as we want the timer to fire 24x7 so that the elapse event is executed only at the requried time
timer.Enabled = true;
}
protected void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) //everytime the elapse event occurs the TimeCheck method will be called
{
TimeCheck();
}
public void TimeCheck() //method to check if the current time is the time we want the archiving to occur
{
var dt = DateTime.Now.Hour;
if(dt==21)
{
Archivefile();
}
}
I wrote little service that check some folder every minute and send the content to FTP folder. inside the service in OnStart method i sets timer for event that runs every minute:
protected override void OnStart(string[] args)
{
aTimer = new Timer();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 60000;
aTimer.Enabled = true;
}
The Event:
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
some logic here....
}
Now my question: is that ok to invoke onStart method only once and let the event do the rest? or should i run onStart method every minute instead of event?
Your application logic which runs every minute, should be inside the event OnTimedEvent.
Read more in Microsoft Documentation here which gives a walkthrough on how to create a Windows Service Application: MS Docs - Walkthrough: Create a Windows service app
is that ok to invoke onStart method only once and let the event do the rest?
Yes, OnStart should be executed only once, which is when your service is started.
or should i run onStart method every minute instead of event?
No, OnStart should run only once.
Suggestion: You might want to increase the time interval, if you are expecting a lot of files or if the file size is going to be large.
I'm trying to write a Windows service that runs indefinitely. Windows forms and background programs for Linux don't seem too bad but maybe I'm just horribly inept at Windows Services. Unlike some other sleep or timer related questions I've dug through here, the time to wake up or sleep can be a regular interval, but isn't always such. The program reads from some data files that may instruct it to change its own schedule and this must take effect as of its next wake up time. It seemed quite easy as a console program and behaved perfectly there:
while (true)
{
// Calculate next time to run.
DateTime nextRun = NextWakeup();
TimeSpan nextTime = nextRun - DateTime.Now;
int sleepMs = (int)nextTime.TotalMilliseconds;
// Sleep until scheduled time
System.Threading.Thread.Sleep(sleepMs);
// Do a code cycle of more stuff here...
}
However, when I try to run it as part of a service so that it continues to be active while the user is logged out, the Service Manager stubbornly refuses to start it. I get the lovely 1053 error, "The service did not respond to the start or control request in a timely fashion."
A lot of answers to related questions here seem to suggest going with a timer at all costs over thread sleeping. If I did such a thing instead of the while/sleep combination, how would I go about changing the timer interval at each run? Or is this all perfectly fine and I'm going about setting up my service wrong?
Much thanks in advance!
Windows services must usually respond to a control request (ususally start/stop but also pause/resume) in 30seconds. This means that if you sleep the main thread in the OnStart your service will return the error you refer to.
The way to resolve your issue is to do your work on a separate thread, where you're free to sleep the thread in the way you describe. Just start this thread in the services' OnStart and you should be able to easily return within the 30 second limit.
As an aside, instead of while(true) you should consider the service being stopped must also return in that 30 second limit. If you have a thread sat sleeping the service will not shut down properly without either Aborting the thread (bad) or providing some mechanism for properly exiting the thread. This is exactly why most people go with the polling approach; the service can both determine whether its time to run, or determine whether a stop request has taken place. As long as this poll freqency is <30s the service will always shut down properly.
If you want to use timers its quite easy to do. I'd use System.Timers.Timer and changing its interval is as easy as mytimer.Inverval = nextTime.Seconds or similar.
I'd personally run the timer without AutoReset = false (so it doesn't restart the timer automatically) and then every time it wakes up it runs your "dowork" and then at the end of the dowork you work out when you want it to run next, set the interval as appropriate and then call Start on your timer again.
Of course in your service your start method just sets up the first timer run and then returns so that the startup is nice and quick. On shutdown you just clean up your timer (stop and dispose and such like) and then just return. Nice and clean.
I think you might be looking for something like this:
static class ConsoleProgram
{
static void Main()
{
ServiceBase[] servicesToRun = new ServiceBase[] { new MyService(config, Logger) };
ServiceBase.Run(servicesToRun);
}
}
public partial class MyService : ServiceBase
{
private bool _stopped = true;
protected override void OnStart(string[] args)
{
StartTimer();
}
protected override void OnStop()
{
StopTimer();
}
public void StartTimer()
{
_stopped = false;
Timer t = new Timer(TimerProc);
// Calculate your desired interval here.
t.Change(_config.Interval, new TimeSpan(0, 0, 0, 0, -1));
}
public void StopTimer()
{
_stopped = true;
}
private void TimerProc(object state)
{
// The state object is the Timer object.
Timer t = (Timer) state;
t.Dispose();
ThreadPool.QueueUserWorkItem(DoWork);
if (!_stopped) {
StartTimer();
}
}
}