C# Windows Service timer ticks more than one - c#

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
}

Related

Use windows service to run a method every on second

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.

Create a .NET Threading.Timer with a period Timeout.Infinite

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(); });.

System.Timers.Timer Restart without AutoReset ignores Intervall

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;
}
}
}
}

Bad timer in Windows service

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.

"new System.Timers.ElapsedEventHandler(DoStuff)" call did not work

I'am trying to create watch folder aplicaction in C# that will do an action when new file will arrive. Since the watched folder is on GPFS share I'am unable to use FileSystemWatcher (which works fine for me in NTFS). So I've based the app on other collegue solution.
The app shows nicely "Timer starts" message but when it comes to
timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
it did not calls the DoStuff method - "Starting new files proc" message never show up. What I've done wrong? Here is complete code:
namespace MonitorFolderActivity
{
public partial class frmMain : Form
{
List<string> fileList = new List<string>();
System.Timers.Timer timer;
DateTime LastChecked;
public frmMain()
{
InitializeComponent();
}
private void abortAcitivityMonitoring()
{
btnStart_Stop.Text = "Start";
txtActivity.Focus();
}
private void startActivityMonitoring(string sPath)
{
if (sPath.Length < 3)
{
MessageBox.Show("You have to enter a folder to monitor.",
"Hey..!", MessageBoxButtons.OK, MessageBoxIcon.Stop);
abortAcitivityMonitoring();
}
else
{
TS_AddLogText(string.Format("Timer starts\r\n"));
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
}
}
private void stopActivityMonitoring()
{
TS_AddLogText(string.Format("Timer stops\r\n"));
this.timer.Stop();
}
private void DoStuff(object sender, System.Timers.ElapsedEventArgs e)
{
TS_AddLogText(string.Format("Starting new files proc\r\n"));
LastChecked = DateTime.Now;
string[] files = System.IO.Directory.GetFiles("D:\\MEDIAIN\\", "*", System.IO.SearchOption.AllDirectories);
foreach (string file in files)
{
if (!fileList.Contains(file))
{
fileList.Add(file);
TS_AddLogText(string.Format(file));
}
}
TimeSpan ts = DateTime.Now.Subtract(LastChecked);
TimeSpan MaxWaitTime = TimeSpan.FromMinutes(1);
if (MaxWaitTime.Subtract(ts).CompareTo(TimeSpan.Zero) > -1)
timer.Interval = MaxWaitTime.Subtract(ts).TotalMilliseconds;
else
timer.Interval = 1;
timer.Start();
}
private delegate void AddLogText(string text);
private void TS_AddLogText(string text)
{
if (this.InvokeRequired)
{
AddLogText del = new AddLogText(TS_AddLogText);
Invoke(del, text);
}
else
{
txtActivity.Text += text;
}
}
private void btnStart_Stop_Click(object sender, EventArgs e)
{
if (btnStart_Stop.Text.Equals("Start"))
{
btnStart_Stop.Text = "Stop";
startActivityMonitoring(txtFolderPath.Text);
}
else
{
btnStart_Stop.Text = "Start";
stopActivityMonitoring();
}
}
private void lblActivity_Click(object sender, EventArgs e)
{
}
private void lblToMonitor_Click(object sender, EventArgs e)
{
}
}
}
There are few issues in your code.
First of all you are not setting the time at which timer should elapse, which means it will read the default value which is
100 ms
Secondly you are not starting your timer. You need to add this line to your code in this method startActivityMonitoring else statement.
timer.Interval = yourdesiredinterval;
timer.Start();
Thirdly, as you are doing stop and start (by looks of your code) you should not create a new timer on each call of your startActivityMonitoring method. Rather you should do this
If(timer == null)
{
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Interval = yourinterval;
timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
}
timer.Start();
In your else clause, you never start the timer. Here's a fix:
else
{
TS_AddLogText(string.Format("Timer starts\r\n"));
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
timer.Start();
}

Categories

Resources