i have timer in my windows service, but the windows service does not do what it should do..
I want ask you, if i have good code with timer?
Part of my code (updated):
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(getFileList);
timer.Interval = 10000;
timer.Enabled = true;
timer.AutoReset = false;
}
private void getFileList(object sender, EventArgs e)
{
//Work with xml...
DeleteOldBackupFiles();
}
private void DeleteOldBackupFiles()
{
string[] Oldfiles = Directory.GetFiles(backup);
foreach (string Ofile in Oldfiles)
{
FileInfo fi = new FileInfo(Ofile);
if (fi.LastWriteTime < DateTime.Now.AddMonths(-2))
{
fi.Delete();
}
}
}
After your ideas i edit my code, but result is the same..
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(getFileList);
timer.Interval = 10000;
timer.Enabled = true;
timer.AutoReset = true;
}
You have most likely an error somewhere in your timer making it throw an exception. You will not detect that since System.Timers.Timer silently ignores all unhandled exceptions.
You'll therefore have to wrap all code with a try/catch block:
private void getFileList(object sender, EventArgs e)
{
try
{
DeleteOldBackupFiles();
}
catch (Exception ex)
{
//log exception or just put a breakpoint here.
}
}
Hence your timer is working, but you are doing something wrong in it.
I would change it to this:
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(getFileList);
timer.Interval = 10000;
timer.AutoReset = false;
timer.Enabled = true;
}
private void getFileList(object sender, EventArgs e)
{
List<string> files = new List<string>();
try
{
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(****);
Setting AutoReset to false causes the Timer to fire just once. In other words, it's like an automatic Stop after the first firing of the Timer. So doing that means you don't need to Stop() the Timer in your getFileList method. This is an important distinction when the Timer interval is small. If you set AutoReset to true and call Stop() at the top of your handler, there's a small chance that your method will get called more than once. Setting AutoReset to false is a more definitive way to get the behaviour you desire.
Calling Start() and setting Enabled to true are redundant, so I removed the Start().
Interval is milliseconds, so I changed that to 10000.
Maybe you are having an Exception thrown somewhere in getFileList, possibly because the service is running with a Current Directory of c:\windows\system32\.
Add a reference to System.Windows.Forms then add Environment.CurrentDirectory = System.Windows.Forms.Application.StartupPath; in your void Main(...) before your service is created.
as #jgauffin pointed out, you should wrap your getFileList body in a 'try catch' and log the error to some absolute path like c:\errors.txt. otherwise you are just guessing whats wrong.
Related
Hi I wrote a method in my program which call a Rest Api and get some information.
I want to call every minute. I fill OnStart and OnStop and all timer_Elapsed in which my method is there. I install my service and start it but It just run just for the first time and never repeat again would if anyone know the solution help me. In advanced I thanked you
On start :
protected override void OnStart(string[] args)
{
///just for log to show program is working
ayandehBLL.Save_Log("Service started...", nameof(OnStart));
if (timer == null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 3000; //*
Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
}
protected override void OnStop()
{
timer.Stop();
timer.Enabled = false;
ayandehBLL.Save_Log("Service stoped", nameof(OnStop));
//WriteErrorLog("Test window service Stoped");
}
-----------------------------
private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
var a = ayandehBLL.GetProductCode();
ayandehBLL.Save_Log($"Request national code is {a}", "test");
if (a != null)
{
Request_DOM request = new Request_DOM();
request.ProductCode= a;
try
{
var result = ayandehBLL.GetMyProductInfo(request);
if (result != null)
{
ayandehBLL.Save_Log(JsonConvert.SerializeObject(result), nameof(OnStart));
}
else
{
ayandehBLL.Save_Log("GetMyProductInfo() returned null", nameof(OnStart));
}
}
catch (Exception ex)
{
ayandehBLL.Save_Log(ex.Message.ToString(), "OnElapsedTime");
}
}
else
{
ayandehBLL.Save_Log("Request national code is null", "OnElapsedTime");
}
//WriteErrorLog("OnElapsedTime done");
}
The method triggered by a timer is being timed and run in a separate thread. If your main thread reaches the program end, the program will stop and the timer is discontinued. Therefore you have to capture the main thread before the end of the program in a loop where the program won't end until you want it to do so.
What I want, a windows service that performs a function with a interval, without opening multiple threads.
What I did, using a Threading.Timer I created the following code:
protected override void OnStart(string[] args) {
System.Threading.Timer timer1 = new System.Threading.Timer(new TimerCallback(Risk), null, 60000, Timeout.Infinite);
}
public void Risk(object state) {
try{
//long operation
}
catch(ex){
}
finally{
timer1.Change(1000, Timeout.Infinite);
}
}
My problem, it looks like this code is opening multiple threads. Is this possible? Where did I go wrong? This a good way to get what I want?
UPDATE (using System.Timers.Timer):
protected override void OnStart(string[] args) {
System.Timers.Timer aTimer;
aTimer = new System.Timers.Timer(60000);
aTimer.Elapsed += Risk;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private void Risk(Object source, ElapsedEventArgs e) {
aTimer.Enabled = false;
try{}
catch(ex){}
finally{
aTimer.Interval = 1000;
aTimer.Enabled = true;
}
}
Multiple timer ticks can run concurrently. The timer class does not wait for ticks to complete. (I think it should have such a feature because it's almost always what you want.)
An easy fix is to run an loop with Task.Delay:
while (!cancel) {
DoStuff();
await Task.Delay(...);
}
And you kick that off with Task.Run(() => { AsyncCodeHere(); });.
I'm trying to make a service that should execute my codes every second after my codes execution ends. But when I start the service and debug it, timer ticks more than one, I mean, my codes executed twice before first execution ends.
here is my codes ;
Timer timer1 = new Timer(1000);
bool _service_working = false;
protected override void OnStart(string[] args)
{
timer1.Elapsed += new ElapsedEventHandler(runProcess);
timer1.Enabled = true;
timer1.Start();
_service_working = false;
}
protected override void OnStop()
{
timer1.Enabled = false;
}
private void runProcess(object sender, ElapsedEventArgs e)
{
try
{
if (_service_working == false)
{
timer1.Enabled=false;
_service_working = true;
}
#region myCodes
}
catch (Exception ex)
{
_logService.insert_log(1022, 2, ex.Message, "Path : runProcess");
}
finally
{
_service_working = false;
timer1.Enabled = true;
}
}
When I debug it, timer ticks again at runProcess if block...
Assuming you're using System.Timers.Timer then Timer events are raised in a background thread usually which means without any locking your timer event methods can overlap.
An easy solution is to set AutoReset to false and instead in your timer event restart it once complete, for example:
private bool terminating;
public Service()
{
terminating = false;
timer = new Timer(1000);
timer.Elapsed += new ElapsedEventHandler(runProcess);
timer.Enabled = true;
timer.AutoReset = false;
}
protected override void OnStart(string[] args)
{
timer.Start();
}
protected override void OnStop()
{
terminating = true;
timer1.Stop();
}
private void runProcess(object sender, ElapsedEventArgs e)
{
// Do stuff
if (!terminating)
timer.Start(); // Restart timer
}
I got a System.Timers.Timer (Even if Threading.Timer is more powerfull, I need the restart option) which should call an Event(Function) for data exchange.
My Timer Init:
private System.Timers.Timer _scheduler; //on class level
_scheduler = new System.Timers.Timer(double.Parse(Config.TimeIntervall));
_scheduler.AutoReset = false;
_scheduler.Elapsed += (o, args) => InterfaceSingleRun();
_scheduler.Start();
The function starts a task, and in the finally statement I got
_scheduler.Start()
to restart my Timer, which should start counting down the intervall again
My Problem: I want to prevent overlapping, because I don't know how long the Task will be running (depends on Server), but the _schedulter.Start() just restarts the Elapsed Event, instead of waiting the intervall time.
Could you please tell me if I just misunderstood the MSDN-Site/the Timer got some issues and how to fix them/or my code is just messed up :)
Thanks
EDIT:
Solved the Problem, thanks to Hans Passant.
I was working with seconds, which the program interpreted as milliseconds.
If i understand correct, you want to prevent a second trigger while the code inside the timer_tick is running.
i use a global bool like this:
class Program
{
private static bool timercodeRunning;
static void Main(string[] args)
{
var timer = new System.Timers.Timer(5000);
timer.Elapsed += timer_Elapsed;
timer.Start();
}
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (!timercodeRunning)
{
timercodeRunning = true;
try
{
//DO SOME STUFF
timercodeRunning = false;
}
catch (Exception)
{
timercodeRunning = false;
throw;
}
}
}
}
instead of bool i recommended you to try locking. here is modified code of Gelootn
class Program
{
private static object timercodeRunning = new object();
static void Main(string[] args)
{
var timer = new System.Timers.Timer(5000);
timer.Elapsed += timer_Elapsed;
timer.Start();
}
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock (timercodeRunning)
{
try
{
//DO SOME STUFF
}
catch (Exception)
{
throw;
}
}
}
}
I have setup a timer:
System.Timers.Timer timer = new System.Timers.Timer (1000);
timer.Enabled = true;
timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
timer.Enabled = false;
ui.CldOnPhoneNumberSent(); // <- this method is not fired
};
the second method is not called.
if i switch the methods as in:
timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
ui.CldOnPhoneNumberSent();
timer.Enabled = false; // <- this method is not called and the timer repeats
}
what's wrong?
Edit:
When the method is called from a timer, it's not called completely!:
timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
((Timer)sender).Enabled = false;
ui.method1();
};
void method1()
{
do something; //<-- called
do Something; //<-- not called
}
It could be a problem with variable closure in the anonymous method - try using the sender value instead of referencing timer:
timer.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => {
((Timer)sender).Enabled = false;
ui.CldOnPhoneNumberSent(); // <- this method is not fired
};
As was said in comments, the most likely reason is that your CldOnPhoneNumberSent() throws some exception preventing further execution.
You should rewrite as follow:
var timer = new System.Timers.Timer (1000);
timer.Elapsed += (sender, args) =>
{
((Timer)sender).Enabled = false;
try
{
ui.CldOnPhoneNumberSent();
}
catch (Exception e)
{
// log exception
// do something with it, eventually rethrow it
}
};
timer.Enabled = true;
Note that is you are inside a WPF application and want to access object created in the UI thread, you may need to dispatch the call:
Action callback = ui.CldOnPhoneNumberSent;
var app = Application.Current;
if (app == null)
{
// This prevents unexpected exceptions being thrown during shutdown (or domain unloading).
return;
}
if (app.CheckAccess())
{
// Already on the correct thread, just execute the action
callback();
}
else
{
// Invoke through the dispatcher
app.Dispatcher.Invoke(callback);
}
As a final note, if you are using .Net 4.5 (with C# 5) you might consider using the async/await pattern instead of System.Timers.Timer, which is easier to use and more readable:
private async Task YourMethod()
{
await Task.Delay(1000)
.ConfigureAwait(continueOnCapturedContext: true); // this makes sure continuation is on the same thread (in your case it should be the UI thread)
try
{
ui.CldOnPhoneNumberSent();
}
catch (Exception e)
{
// log exception
// do something with it, eventually rethrow it
}
}