I need to make a timer fire at the end of each month.
I have written a small program that has code that needs to be executed at the last day of each month and I have no idea how to implement it. I suggested to my boss using windows scheduler but he wants it done in code with timer.
So how do I do this ?
I managed to persuade the boss to use windows scheduled tasks. There is a way to do this with a timer. I include the code here below. It is quick and dirty. Note strongly that Using Scheduled tasks IS the correct way to implement this kind of task.
private Timer timer;
public MyClass()
{
timer = new Timer();
timer.Elapsed += TimerElapsed;
}
private void TimerElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
if (DateTime.Now.Day == DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month))// is it the last day of this month
{
ClientStatsController.FireAll();
}
Thread.Sleep(TimeSpan.FromMinutes(5));
timer.Interval = CalculateInterval();
TimeSpan interval = new TimeSpan(0, 0, 0, 0, (int)timer.Interval);
}
// Helper functions
private static TimeSpan From24HourFormat(string value)
{
int hours = Convert.ToInt32(value.Substring(0, 2));
int mins = Convert.ToInt32(value.Substring(2, 2));
return TimeSpan.FromHours(hours) + TimeSpan.FromMinutes(mins);
}
private double CalculateInterval()
{
string runtimeValue = ConfigController.AppSettings["runTime"]; // just a simple runtime string like 0800
double runTime = From24HourFormat(runtimeValue).TotalMilliseconds;
if (DateTime.Now.TimeOfDay.TotalMilliseconds < runTime)
{
return runTime - DateTime.Now.TimeOfDay.TotalMilliseconds;
}
else
{
return (From24HourFormat("2359").TotalMilliseconds - DateTime.Now.TimeOfDay.TotalMilliseconds) + runTime;
}
}
EDIT
I started going through all my older questions and answers.
Using a timer is a very bad idea. For scheduled tasks you want to use exaclty that. A scheduler. Windows provides a decent task scheduler, but if you have more complex scheduling logic and background tasks, it is better to use a proper third party library.
The two outstanding ones for .NET are Hangfire and Quartz.
Hangfire comes complete with a dashboard and is super easy to implement, especially if your working on the .NET core platform.
Quartz is also a very nice solution, and it has more scheduling options and better suited for complicated scheduling logic than Hangfire.
The proposed solution is indeed a very bad on, coming from an intern who just started working. I am happy to go back in time and realize how things can be done differently and better.
Related
I have a code with which I am reading in 35ms intervals the current and position values of a machine's CNC axis from a remote computer.
The data is read from the CNC/PLC control system of the machine
My C# code has to run on our company server with Windows Server 2019. I am sending the data to Kafka, our AI experts have to interpret the current and position curve shapes for an AI algorithm. So the data has to be read every 35 ms as precise as possible
Normally I have used first a system timer with a 35ms period. It seems to work but I am not sure if this is the best way. Is there a more precise method than using a system timer?
My code
public void Main()
{
InitializeTimer_1();
}
public void InitializeTimer_1()
{
System.Timers.Timer timer1 = new System.Timers.Timer();
timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent1);
timer1.Interval = 35;
timer1.Enabled = true;
}
public void OnTimedEvent1(object sender, EventArgs e)
{
// my Data reading code
}
There are multiple ways to solve this problem.
It first depends on what kind of application you have.
If you have a console app then you can schedule it to run every 35ms using the windows task scheduler and it will work.
If it is a long-running process like windows service then you can use the same code you have
There is one very useful library hangfire, you can explore this as well.
Also, refer to this post as well, you may get more directions.
Edit: System.Timers.Timer is sufficient for most the purpose, you could also consider System.Threading.Timer for short intervals, it allows more precise timings but its will run on a separate thread so keep that in mind. There is one more option System.Diagnostics.Stopwatch which has more high precision than other approaches.
The actual precision of the timer also depends on hardware, OS and the workload on the machine.
Now you can evaluate all the approaches and chose the best one for you.
The timer accepts a direct callback method. If you want to execute something periodic, it can be done as follows:
var timer = new Timer(TimerCallback, state, startAfterTimeSpan, repeatTimeSpan);
Where you can e.g. write a method
private void TimerCallback(object state)
{
// do something
}
I'm making a simple game on console for practice that requires a time limit each round and I've encountered a problem with trying to make it so I can use timer more than once. I have this:
class Program
{
static Timer timer = new Timer(1000);
static int t = 10;
static void Main(string[] args)
{
timer.Elapsed += Timer_Elapsed1;
timer.Start();
Console.ReadLine();
t = 10;
timer.Start();
Console.ReadLine();
}
My thoughts were that the 2nd timer.Start() would get the same result as the first, but nothing happens.
private static void Timer_Elapsed1(object sender, ElapsedEventArgs e)
{
t--;
Console.WriteLine("Hello!");
if (t == 0)
{
Console.WriteLine("Goodbye!");
timer.Stop();
}
}
Why is the second timer.Start() not doing anything? How do I make it so I can use timer.Start() again and it will do the same thing as the first time? I'm using System.Timers
NVM IT DOES WORK, IM JUST DUMB LOL
Try stopping or disabling the first timer before trying to start a second time.
C# - how do you stop a timer?
I fell compelled to give you some disclaimers:
First, console is not the right Environment for Game Development. Neither is any of the GUI techs. For games you got XNA (pretty dated) and with .NET Core a bunch of new Options. The important thing is that you have a Game Loop of some form. Or at least imitate one.
Secondly, I am unsure how well most Timers work in console apps. Most of them use callbacks wich usually require a MessageQueue - wich is a GUI feature. I guess you could try a Multithreading time, but then you have to relearn everything if you leave Console applications.
As for your code: I am unsure when the Timer tick happens since you specified no interval. But I guess either:
never
after the 2nd timer start
I need code that will provide "Ticks" of 10 miliseconds exactly and I am buffled in view of the many articles some contradicting others regarding how to accomplish this in Windows.
I've managed the first step - using the MultiMedia timer to provide sleeps of 1 mili.
Is there a way to ensure that the sleep code will work on all machines IsHighResolution either true or false, single or multi processor systems etc?
[edit]
A previous question ragarding the problem with using StopWatch in a multicore system:
Multicore and thread aware .Net stopwatch?
[/edit]
sorry that I can't write this in comments...
If you have the possibility to use a second thread you could
use a loop to waste the time...like this:
class yourTimer{
public void startTimer(Action a)
{
ParameterizedThreadStart fu = new ParameterizedThreadStart(waiter);
Thread t1 = new Thread(fu);
t1.Start(a);
}
public void stopTimer()
private void waiter(object o)
{
Action ac = (Action)o;
while(waitin)
{
if(DateTime.Now.Millisecond%10==0)
{
ac.Invoke();
}
continue;
}
}
}
but that's a quite ugly solution I think ...
For good understanding I will take a simple abstraction of DHCP lease as example: The lease contains the IP and MAC address, the time it was granted at and can be renewed with a given time span. Once expired an event will be invoked. Again, this is just serving as the most minimal example I could come up with:
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Timers;
namespace Example
{
public class Lease
{
public IPAddress IP
{
get;
private set;
}
public PhysicalAddress MAC
{
get;
private set;
}
public DateTime Granted
{
get;
private set;
}
public event EventHandler Expired;
private readonly Timer timer;
public Lease(IPAddress ip, PhysicalAddress mac, TimeSpan available)
{
IP = ip;
MAC = mac;
timer = new Timer();
timer.AutoReset = false;
timer.Elapsed += timerElapsed;
Renew(available);
}
public void timerElapsed(object sender, EventArgs e)
{
var handle = Expired;
if (handle != null)
{
handle(this, EventArgs.Empty);
}
}
public void Renew(TimeSpan available)
{
Granted = DateTime.Now;
timer.Interval = available.TotalMilliseconds;
timer.Enabled = true;
}
}
}
Is there anything to consider when creating - for example - "a few thousand" instances of such a class? I am mostly concerned about the timers. Should I consider another design pattern for such a task (like a manager for all the leases,or not use timers at all?) or is there nothing to worry about when creating a lot of timers, and this is the appropriate way? At least I always try to be cautious when it comes to timers and events.
Rather than creating thousands of timers, you could just store the expiration time of each Lease object, then in a single thread query for the expired ones periodically.
An off the top of my head code example:
var leases = new List<Lease>();
var running = true;
var expiredChecker = Task.Factory.StartNew(() =>
{
while (running)
{
var expired = leases.All(l => l.ExpirationDate < DateTime.Now);
// do something with the expired lease objects
}
});
Assuming you have an IEnumerable<Lease>, a DateTime property called ExpirationDate on your Lease object, you can then cancel this by setting running to false when you want to stop.
I would suppose this depends partly on what resources you have available on your server, and what kind of accuracy and performance you need.
An alternative approach might be to store something as simple as a time stamp in each instance, and checking that value regularly, comparing it to current time, and updating it appropriately. I have a hunch that this might be easier on performance - but you should try to benchmark it somehow to be sure.
Of course, if you have a large number of instances, iterating over all of them might also take some time, so perhaps pooling these into groups, where each group is handled in a separate thread on regular (adjustable?) intervals might be an option.
It's a bit hard to give a great answer here without some info about performance, so you should probably just create a proof of concept, and test a couple of strategies that you think might work, and try to benchmark them to see which fits best.
According to the System.Timers.Timer MSDN page:
The server-based Timer is designed for use with worker threads in a
multithreaded environment. Server timers can move among threads to
handle the raised Elapsed event, resulting in more accuracy than
Windows timers in raising the event on time.
Which means it is not very likely to be causing issues when you are running a couple thousand timers at the same time.
That doesn't mean it is a good approach, you should probably be looking for a more centralized solution to this problem.
I recommend use a System.Threading.Timer instead of the System.Timers.Timer. The second one is wrapper about the first one to be visible in the design time and it is not necessary if you really don't need design time support. Timer internally calls ThreadPool.QueueUseWorkItem, than threadpool is responsible for maintaining thread on timer tick. Thread pool uses only one thread to maintain all the timers object and this thread decide when each timer queue new thread on timer tick.
Than I cant see any overhead unless your timers will tick so quick than you are not able do all on tick job and you simply queue too much work in thread pool.
I'm using System.Timers.Timer in my WPF application. I want to understand how Timer does behave, after Computer is hibernated, and sleep. I'm getting some weird issues with my application, after computer is getting resumed from hibernate.
How should I handle timers, and how do they behave when computer is in hibernate/sleep mode?
I have a midnight timer which should work each midnight to reset the default values on UI.
Here is the code that creates the timer:
private void ResetMidnightTimer()
{
// kill the old timer
DisposeMidnightTimer();
_midnightTimer = new Timer();
// scheduling the timer to elapse 1 minute after midnight
_midnightTimer.Interval = (DateTime.Today.AddDays(1).AddMinutes(1) - DateTime.Now).TotalMilliseconds;
_midnightTimer.Elapsed += (_, __) => UpdateRecommendedCollectingTime();
_midnightTimer.Enabled = true;
_midnightTimer.Start();
}
On UI page's contructor, I call the method which calls ResestMidnightTimer() and creates the timer de facto. After that the timer just waits for the night.
When the night time (actually it is the 12:01 AM) comes, the timer works, resets the default values as expected and then disposes existing timer. Finally it creates a new midnight timer for next day.
But if I try to hibernate the computer during that day, the midnight timer won't work and won't reset the default values.
Is that because while hibernating it just postpones the event handling by the same amount of time it was hibernated?
This depends on how you are using your timers. If you are using them to initiate some event that occurs infrequently (greater than a couple minutes) then you will probably see some 'weird' behavior. Since you don't specify what that 'weird' behavior is, I'm going to assume that your program's timer goes off later than it should.
Explanation: The problem with going to sleep/hibernating is that all programs are suspended. This means that your Timers are not being updated and thus when you sleep/hibernate and come back, it is as if you were frozen for that period of time that you were sleeping/hibernating. This means if you have a timer set to go off in an hour and your computer goes to sleep at the 15 minute mark, once it wakes up it will have another 45 minutes to go, regardless of how long the computer was sleeping.
Solution: One fix would be to keep a DateTime around of the last time the event occurred. Then, have a timer go off periodically (every 10 seconds or 10 minutes, depending on the precision desired) and check the DateTime of the last execution. If the difference between now and the last execution time is greater than or equal to the interval desired, THEN you run execution.
This will fix it so that if an event 'should have' occurred during sleeping/hibernating, it will start the moment you return from sleeping/hibernating.
Update: The solution presented above will work and I'll fill in a couple of details to help you implement it.
Instead of creating/disposing of new Timers, create ONE timer to use that is RECURRING (the AutoReset property is set to true)
The interval of the single timer should NOT be set according to the next time the event should occur. Instead, it should be set to a value you choose that will represent the polling frequency (how often it checks to see if the 'event' should run). The choice should be a balance of efficiency and precision. If you NEED it to run REALLY close to 12:01 AM then you set the interval to around 5-10 seconds. If it is less important that it be at exactly 12:01 AM, you can increase the interval to something like 1-10 minutes.
You need to keep around a DateTime of when the last execution occurred OR when the next execution should happen. I would prefer 'when the next execution should happen' so that you aren't doing (LastExecutionTime + EventInterval) each time the timer elapses, you'll just be comparing the current time and the time the event should occur.
Once the timer elapses and the event SHOULD occur (somewhere around 12:01 AM), you should update the stored DateTime and then run the code you want run at 12:01 AM.
Sleep vs. Hibernate Clarification: The main difference between sleep and hibernate is that in sleep, everything is kept in RAM whereas hibernate saves the current state to disk. The main advantage of hibernate is that the RAM no longer needs power and thus expends less energy. This is why it is recommended to use hibernate over sleep when dealing with laptops or other devices using a finite amount of energy.
That said, there is no difference in the execution of programs as they are being suspended in either case. Unfortunately, the System.Timers.Timer does not 'wake up' a computer and so you can't enforce your code to be run at ~12:01 AM.
I believe there are OTHER ways to 'wake up' a computer but unless you go that route the best you can do is run your 'event' during the next 'polling event' of your timer after it comes out of sleep/hibernate.
Is that because while hibernating it just postpones the event handling by the same amount of time it was hibernated?
While the computer is in a suspended mode (i.e. sleep or hibernate), it doesn't do anything. This includes, in particular, the scheduler that handles waking up the thread that is monitoring the queue of timer events isn't running and so that thread isn't making any progress towards resuming execution to handle the next timer.
It's not so much that the event is explicitly postponed per se. But yes, that's the net effect.
In some cases, it's possible to use a timer class that doesn't have this issue. Both System.Windows.Forms.Timer and System.Windows.Threading.DispatcherTimer are based not on the Windows thread scheduler, but instead on the WM_TIMER message. Because of the way this message works — it is generated "on the fly" when a thread's message loop checks the message queue, based on whether the expiration time for the timer has passed…in a way, it's similar to the polling work-around described in the other answer to your question — it's immune to delays that would otherwise be caused by the computer being suspended.
You've stated your scenario involves a WPF program, so you may find that your best solution is actually to use the DispatcherTimer class, instead of System.Timers.Timer.
If you do decide you need a timer implementation that isn't tied to the UI thread, here's a version of System.Threading.Timer that will correctly take into account time spend while suspended:
class SleepAwareTimer : IDisposable
{
private readonly Timer _timer;
private TimeSpan _dueTime;
private TimeSpan _period;
private DateTime _nextTick;
private bool _resuming;
public SleepAwareTimer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
{
_dueTime = dueTime;
_period = period;
_nextTick = DateTime.UtcNow + dueTime;
SystemEvents.PowerModeChanged += _OnPowerModeChanged;
_timer = new System.Threading.Timer(o =>
{
_nextTick = DateTime.UtcNow + _period;
if (_resuming)
{
_timer.Change(_period, _period);
_resuming = false;
}
callback(o);
}, state, dueTime, period);
}
private void _OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
if (e.Mode == PowerModes.Resume)
{
TimeSpan dueTime = _nextTick - DateTime.UtcNow;
if (dueTime < TimeSpan.Zero)
{
dueTime = TimeSpan.Zero;
}
_timer.Change(dueTime, _period);
_resuming = true;
}
}
public void Change(TimeSpan dueTime, TimeSpan period)
{
_dueTime = dueTime;
_period = period;
_nextTick = DateTime.UtcNow + _dueTime;
_resuming = false;
_timer.Change(dueTime, period);
}
public void Dispose()
{
SystemEvents.PowerModeChanged -= _OnPowerModeChanged;
_timer.Dispose();
}
}
The public interface for System.Threading.Timer, and the subset interface above copied from that class, is different from what you'll find on System.Timers.Timer, but it accomplishes the same thing. If you really want a class that works exactly like System.Timers.Timer, it should not be hard to adapt the above technique to suit your needs.
System.Timers.Timer is a server based timer(elapsed event uses Threadpool. More accurate than other timers). When your computer goes in sleep mode or in hibernate mode, all the state of your program are stored in RAM. Same goes for your application state. Once your system is up your application state will be restored (along with the timer) by the OS. It wont be a good idea to "do something" or try to detect this events. Its possible from a Windows service though. Leave it to the OS to do its job.
An simple alarm class accepting an absolute Utc time that will survive a sleep cycle. The alarm can then be adjusted from the alarm callback to go off again. No periodic mode is supported to keep it simple. Based strongly on the answer from #PeterDuniho. Full disclosure: minimally tested.
using Microsoft.Win32;
using System;
using System.Threading;
class AlarmSleepTolerant : IDisposable
{
readonly Timer _timer;
DateTime? _alarmUtcOpt;
/// <summary>
/// Constructor
/// </summary>
/// <param name="callback"></param>
/// <param name="alarmUtcOpt"></param>
/// <param name="stateOpt"></param>
public AlarmSleepTolerant(TimerCallback callback, DateTime? alarmUtcOpt = null, object stateOpt = null)
{
SystemEvents.PowerModeChanged += _OnPowerModeChanged;
_timer = new Timer(callback, stateOpt, Timeout.Infinite, Timeout.Infinite);
SetAlarmTime(alarmUtcOpt);
}
/// <summary>
/// Set the current alarm, if alarmUtc is <= UtcNow, then the alarm goes off immediately.
/// Pass null to disable the alarm.
/// </summary>
/// <param name="alarmUtc"></param>
public void SetAlarmTime(DateTime? alarmUtcOpt = null)
{
lock (_timer)
{
_alarmUtcOpt = alarmUtcOpt;
if (!alarmUtcOpt.HasValue)
{
_timer.Change(Timeout.Infinite, Timeout.Infinite); // disables the timer
}
else
{
TimeSpan dueIn = _alarmUtcOpt.Value - DateTime.UtcNow;
_timer.Change(dueIn.Ticks <= 0 ? 0 : (long)dueIn.TotalMilliseconds, Timeout.Infinite);
}
}
}
public void Dispose()
{
SystemEvents.PowerModeChanged -= _OnPowerModeChanged;
_timer.Dispose();
}
void _OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
// Timers are based on intervals rather than absolute times so they
// need to be adjusted upon a resume from sleep.
//
// If the alarm callback was missed during sleep, it will be called now.
//
if (e.Mode == PowerModes.Resume)
{
lock (_timer)
SetAlarmTime(_alarmUtcOpt);
}
}
}