I have a server which listens to clients in a while(true) loop.
I keep every client's hostname in a list and save the time the client contact the server.
I would like to check every 10 minutes if some of the clients didn't contact the server in the last hour and to print its name.
I thought about doing something like this:
Task.Run(CheckTheClients()) //Check the passed-time of each client in the list
while(true)
{
//listen to clients, add them to list, etc.
}
But I'm not sure how to do the check every 10 minutes and not every millisecond, neither if my idea is good or not.
So What is the best way to do this?
Moreover, both the function and the while(true) touches the list of the clients. Is that going to make some problems?
This would be best done by using the Timer function, basically you create it, pass it a function to call at each amount of time passed, and set the time to wait in Milliseconds. So for your example of 10 minutes, something like this:
// insert this into a long running function, and scope the timer variable correctly
System.Timers.Timer myTimer = new System.Timers.Timer();
myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
myTimer.Interval = 600000;
myTimer.Enabled = true;
// Define what you want to happen when the Elapsed event occurs (happens on the interval you set).
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//do some work here
}
You can put your thread to sleep, like this:
while (true)
{
try
{
// do something
}
catch (Exception ex)
{
// save log
}
Thread.Sleep(TimeSpan.FromMilliseconds(TimeSpan.FromMinutes(10).TotalMilliseconds));
}
Since you're using Task.Run in the sample code you provided, why not use Task.Delay while you're at it?
Action CheckTheClients = () => Console.WriteLine("Checking clients...");
while (true)
{
var task = Task.Delay(1000).ContinueWith(x => CheckTheClients());
await task;
}
No need to sign up for timer and its events, if you're going for simplicity.
I have a service written in C# (.NET 1.1) and want it to perform some cleanup actions at midnight every night. I have to keep all code contained within the service, so what's the easiest way to accomplish this? Use of Thread.Sleep() and checking for the time rolling over?
I wouldn't use Thread.Sleep(). Either use a scheduled task (as others have mentioned), or set up a timer inside your service, which fires periodically (every 10 minutes for example) and check if the date changed since the last run:
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
protected override void OnStart(string[] args)
{
_timer = new Timer(10 * 60 * 1000); // every 10 minutes
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start();
//...
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// ignore the time, just compare the date
if (_lastRun.Date < DateTime.Now.Date)
{
// stop the timer while we are running the cleanup task
_timer.Stop();
//
// do cleanup stuff
//
_lastRun = DateTime.Now;
_timer.Start();
}
}
Check out Quartz.NET. You can use it within a Windows service. It allows you to run a job based on a configured schedule, and it even supports a simple "cron job" syntax. I've had a lot of success with it.
Here's a quick example of its usage:
// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();
// Instantiate the JobDetail object passing in the type of your
// custom job class. Your class merely needs to implement a simple
// interface with a single method called "Execute".
var job = new JobDetail("job1", "group1", typeof(MyJobClass));
// Instantiate a trigger using the basic cron syntax.
// This tells it to run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
"trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");
// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);
A daily task? Sounds like it should just be a scheduled task (control panel) - no need for a service here.
Does it have to be an actual service? Can you just use the built in scheduled tasks in the windows control panel.
The way I accomplish this is with a timer.
Run a server timer, have it check the Hour/Minute every 60 seconds.
If it's the right Hour/Minute, then run your process.
I actually have this abstracted out into a base class I call OnceADayRunner.
Let me clean up the code a bit and I'll post it here.
private void OnceADayRunnerTimer_Elapsed(object sender, ElapsedEventArgs e)
{
using (NDC.Push(GetType().Name))
{
try
{
log.DebugFormat("Checking if it's time to process at: {0}", e.SignalTime);
log.DebugFormat("IsTestMode: {0}", IsTestMode);
if ((e.SignalTime.Minute == MinuteToCheck && e.SignalTime.Hour == HourToCheck) || IsTestMode)
{
log.InfoFormat("Processing at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
OnceADayTimer.Enabled = false;
OnceADayMethod();
OnceADayTimer.Enabled = true;
IsTestMode = false;
}
else
{
log.DebugFormat("Not correct time at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
}
}
catch (Exception ex)
{
OnceADayTimer.Enabled = true;
log.Error(ex.ToString());
}
OnceADayTimer.Start();
}
}
The beef of the method is in the e.SignalTime.Minute/Hour check.
There are hooks in there for testing, etc. but this is what your elapsed timer could look like to make it all work.
As others already wrote, a timer is the best option in the scenario you described.
Depending on your exact requirements, checking the current time every minute may not be necessary.
If you do not need to perform the action exactly at midnight, but just within one hour after midnight, you can go for Martin's approach of only checking if the date has changed.
If the reason you want to perform your action at midnight is that you expect a low workload on your computer, better take care: The same assumption is often made by others, and suddenly you have 100 cleanup actions kicking off between 0:00 and 0:01 a.m.
In that case you should consider starting your cleanup at a different time. I usually do those things not at clock hour, but at half hours (1.30 a.m. being my personal preference)
I would suggest that you use a timer, but set it to check every 45 seconds, not minute. Otherwise you can run into situations where with heavy load, the check for a particular minute is missed, because between the time the timer triggers and the time your code runs and checks the current time, you might have missed the target minute.
You can also try the TaskSchedulerLibrary here http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8
Implement the abstract class AbstractScheduledTask and call the ScheduleUtilityFactory.AddScheduleTaskToBatch static method
For those that found the above solutions not working, it's because you may have a this inside your class, which implies an extension method which, as the error message says, only makes sense on a non-generic static class. Your class isn't static. This doesn't seem to be something that makes sense as an extension method, since it's acting on the instance in question, so remove the this.
Try this:
public partial class Service : ServiceBase
{
private Timer timer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
SetTimer();
}
private void SetTimer()
{
if (timer == null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 60000 * Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
}
private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
//Do some thing logic here
}
protected override void OnStop()
{
// disposed all service objects
}
}
My company has developed a Windows Service Application and it was installed in some customers.
They are complaining that the Service stops after continuously running for a few days.
I can't reproduce the error and I do not have any stack trace. All I have is a generic message in Event Viewer:
The 'myservicename' service terminated unexpectedly. It has done this 1 time(s).
My code:
private System.Timers.Timer myTimer;
private readonly Queue<FileInfo> MyQueue = new Queue<FileInfo>();
protected override void OnStart(string[] args)
{
myTimer = new System.Timers.Timer(1000 * 60 * 1); // 1 min
myTimer.Elapsed += new ElapsedEventHandler(MyMethod);
myTimer.Start();
SomeSafeTasks();
try
{
CreateSomeThreads();
}
catch(Exception)
{
//log
}
}
public void MyMethod()
{
lock (MyQueue) // there are other places with lock
{
if(MyQueue.Count == 0)
{
// code with try catch
}
}
}
I believe that the error is related with the Timer being GC'ed.
Does it make sense? The code above may break after running some days?
How do I estimate when it will break? It is strange for me that it runs for a week. I would expect that it would be GC'ed in 15 minutes or 1 hour.
Is it 100% safe to add GC.KeepAlive(myTimer) after myTimer.Start()?
Will it run forever or do I need to call GC.KeepAlive sometimes?
So I'm trying to run an event every 5 seconds. Seems to work using System.Timers.Timer to some extend but it seems to be skipping sometimes, not even responding late, just plain skipping it.
Anything I could do about this?
internal void DetermineScreenCapping()
{
System.Timers.Timer ScreenCapTimer = new System.Timers.Timer();
/// Initialize the screencapper (doesn't enable it yet)
// Tell the timer what top do when it elapses
ScreenCapTimer.Elapsed += new ElapsedEventHandler(ExecuteCode);
// Set it to go off every five seconds
ScreenCapTimer.Interval = 5000;
// And start it
ScreenCapTimer.Enabled = true;
}
private void ExecuteCode(object source, ElapsedEventArgs e)
{
if (IsCurrentlyWorking == true)
{
Execute Code
}
}
The problem indeed wasn't the timer not doing it's job. It was the code being executed that had some problems that couldn't even be seen debugging for some reason.
I changed the code and the timer works properly now ^^
I would like to run a function (funcA) and use another function (timerFunc) as a timer. If the running function (funcA) has run for 10 seconds, I would like to exit it using the timer function (timerFunc). Is this possible? Basically what I am trying to do:
void funcA() {
// check event 1
// check event 2
// check event 3
// time reaches max here! --exit--
//check event 4
}
If not, what is the best way to handle such scenarios? I have considered using a stop-watch but I'm not sure if that is the best thing to do, mainly because I do not know after what event the timeout will be reached.
Thread t = new Thread(LongProcess);
t.Start();
if (t.Join(10 * 1000) == false)
{
t.Abort();
}
//You are here in at most 10 seconds
void LongProcess()
{
try
{
Console.WriteLine("Start");
Thread.Sleep(60 * 1000);
Console.WriteLine("End");
}
catch (ThreadAbortException)
{
Console.WriteLine("Aborted");
}
}
You could put all of the events into an array of Action or other type of delegate, then loop over the list and exit at the appropriate time.
Alternately, run all of the events in a background thread or Task or some other threading mechanism, and abort/exit the thread when you get to the appropriate time. A hard abort is a bad choice, as it can cause leaks, or deadlocks, but you could check CancellationToken or something else at appropriate times.
I would create a list and then very quickyl:
class Program
{
static private bool stop = false;
static void Main(string[] args)
{
Timer tim = new Timer(10000);
tim.Elapsed += new ElapsedEventHandler(tim_Elapsed);
tim.Start();
int eventIndex = 0;
foreach(Event ev in EventList)
{
//Check ev
// see if the bool was set to true
if (stop)
break;
}
}
static void tim_Elapsed(object sender, ElapsedEventArgs e)
{
stop = true;
}
}
This should work for a simple scenario. If it's more complex, we might need more details.