Having a few problems with Timers within a service on Win2k3...
Basically, creating a service that every X minutes/seconds, checks for a certain process and whether it is running. I figured the easiest way to get this done was via a Timer.
Have managed to install the service fine, and it seems to be reporting that it is starting/stopping OK. I have written to the eventlog using Eventlog.WriteEntry, and have observed that it is reaching the startup function, but not the Timer Tick.
EventLog.WriteEntry("SETTINGS SET");
// Set our timer's interval to the value set in the settings.xml file.
tmrCheck.Interval = Int32.Parse(_settingChkInterval) * 1000;
// Enable our timer and away we go, checking away!
tmrCheck.Enabled = true;
// Set our Tick event to our Tick void
tmrCheck.Tick += new EventHandler(tmrCheck_Tick_1);
Mmmm, you cant use a Winform timer in a service.
You need to use System.Timers.Timer or System.Threading.Timer.
Related
There's some strange mistake with timer and forms.
I am making editor for game. Editor has two forms - MainForm and PreviewForm. PreviewForm contains only control for OpenGL output (Custom control based on GLControl from OpenTK), named glSurface.
glSurface has two inline timers (Windows.Forms.Timer) - one for rendering, and one for updating game state. Timers fires in glSurface method Run(double updateRate, double frameRate).
So, I want to show PreviewForm and run updating and rendering from MainForm.
My code is:
PreviewForm = new PreviewForm();
PreviewForm.glSurface.Run(60d, 60d);
PreviewForm.Show(this); //Form is "modal"
Body of Run method:
if (Running)
throw new Exception("Already run");
_updateRate = updateRate;
_renderRate = frameRate;
var renderFrames = Convert.ToInt32(1000/frameRate);
var updateFrames = Convert.ToInt32(1000/updateRate);
RenderTimer.Interval = renderFrames;
UpdateTimer.Interval = updateFrames;
RenderTimer.Start();
UpdateTimer.Start();
Running = true;
Timers is being initialized in OnVisibleChanged event:
protected override void OnVisibleChanged(EventArgs e)
{
...
RenderTimer = new Timer();
UpdateTimer = new Timer();
RenderTimer.Tick += RenderTick;
UpdateTimer.Tick += UpdateTick;
...
}
Weird things start here.
When PreviewForm is showing, nothing happens. BUT when I close that form, both timers fire their events! I have tested for possible cross-thread interaction, but PreviewForm.InvokeRequired and glSurface.InvokeRequired are both false.
Please help me find out what the hell is going on.
In this case declare and initialise and start your timers all within the one code block:
{
.../...
RenderTimer = new Timer();
UpdateTimer = new Timer();
RenderTimer.Tick += RenderTick;
UpdateTimer.Tick += UpdateTick;
var renderFrames = Convert.ToInt32(1000/frameRate);
var updateFrames = Convert.ToInt32(1000/updateRate);
RenderTimer.Interval = renderFrames;
UpdateTimer.Interval = updateFrames;
RenderTimer.Start();
UpdateTimer.Start();
.../...
}
Without seeing the program flow this is the safest option. It appears the variables are local to the OnVisibleChanged event, so I'm not sure how you're not getting a null refernce exception when you're calling them from your if (Running).
The other thing you could do is make them class variables and ensure they are initialised before you use them. Then call start within the if statement.
As for the issue of them starting when the form closes, it's impossible to determine from the code you've shown.
Edit: There's a deeper problem.
You really shouldn't be using system timers to drive your game updates and rendering.
System timers on most platforms have low accuracy that's inadequate for high performance multimedia such as audio and most games. On Windows System.Windows.Forms.Timer uses Win32 timers which have particularly low accuracy, typically resulting in intervals at least 15ms off(see this answer). See this technical breakdown and this overview for more information. Basically, even if your code worked correctly your frames would stutter.
Most games "tick" by running an infinite loop in the main thread, doing the following each time(not necessarily in this order):
Call back into the framework to handle pending OS events.
Track the time difference since the last "tick" so frame-independent timing works.
Update the state of the game(such as physics and game logic, possibly in another thread).
Render the scene based on a previous update(possibly in another thread).
As noted by commenters, the main problem in your timer code is that initialization is split between Run and OnVisibleChanged. I was unable to reproduce the case where the timer fires after a sub form is closed. I suspect some other code you haven't posted is the cause. You'll save yourself a great deal of trouble if you use OpenTK.GameWindow. It handles the loop plumping for you, similar to XNA. This is an example of one way to integrate it with WinForms. See the manual for more information.
In Run, you set Interval and start each timer. No Tick callbacks are set. In OnVisibleChanged, you recreate the timers and assign Tick callbacks. No intervals are set, and the timer's haven't been started.
The timer initialization code in Run is essentially ignored because no tick callbacks are set and OnVisibleChanged recreates the timers. OnVisibleChanged triggers almost immediately after Run, shortly after you call PreviewForm.Show(this).
If you're dead set on using system timers, this should work:
// somewhere before Run(ideally in the initialization of the main form).
RenderTimer.Interval = Convert.ToInt32(1000 / frameRate);
RenderTimer.Tick += RenderTick;
UpdateTimer.Interval = Convert.ToInt32(1000 / updateRate);
UpdateTimer.Tick += UpdateTick;
void Run(double frameRate, double updateRate)
{
// ...
RenderTimer.Start();
UpdateTimer.Start();
// ...
Running = true;
}
// ...
protected override void OnVisibleChanged(EventArgs e)
{
// ...
// Don't initialize timers here.
// ...
}
After lot of googling and spending 4 hours I guess this is the best way to find user inactive and lock screen.
public MainWindow()
{
InitializeComponent();
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(10) };
timer.Tick += delegate
{
timer.Stop();
MessageBox.Show("Logoff trigger");
timer.Start();
};
timer.Start();
InputManager.Current.PostProcessInput += delegate(object s, ProcessInputEventArgs r)
{
if (r.StagingItem.Input is MouseButtonEventArgs || r.StagingItem.Input is KeyEventArgs)
timer.Interval = TimeSpan.FromSeconds(10);
};
}
If your question is, "Is there a better way to implement a session timeout?" - then I would say, possibly - this is how I do it.
A session timeout can do one of two things. It can work like an arcade game where you have a timeout duration in which to complete your tasks. Or it can monitor for inactivity and close if nothing happens.
Either way, I would wrap this functionality into a session provider - assuming MVVM is the goal, I use provider to refer to a service or data source of some sort.
The provider gets instantiated as a singleton and so exists as one instance throughout the app life cycle. I usually manage this by creating it in app.xaml. I then interact with the provider using a message framework such as MVVM light.
Once created the provider manages a thread which checks a datetime to see if it occurs in the past. If it does it issues a session over event or message. This message is picked up by your application to shut down or whatever.
If you want a finite period or time, you implement a start message which sets the monitored date time to a point in the future according to the time span you want to run. If you want an inactivity log out then you send this message from whatever user interactions you see fit to prevent log out such as input changes or ICommand executes.
I take this a stage further so my provider also issues an 'ending' message a few seconds before the timeout completes so I can display a warning - but hopefully you get the general idea.
If this sounds like what you're after then I will add in some examples, but haven't so far in case this is not what you're asking.
I have a Windows service that polls a remote FTP server every three seconds. It checks a directory for files, downloads any files present, and deletes those files once downloaded. Average file size is 10 KB, and rarely they will go up to the 100 KB range.
Occasionally (I have noticed no pattern), the WebClient will throw the following:
System.Net.WebException: The operation has timed out.
at System.Net.WebClient.OpenRead(Uri address)
It will do this for one or more files, usually whatever files are in the remote directory at that time. It will continue to do so indefinitely, churning on the "stuck" files at each polling interval. The bizarre part is that when I stop/start the Windows service, the "stuck" files download perfectly and the polling/downloading works again for long stretches of time. This is bizarre because I download like this:
private object _pollingLock = new object();
public void PollingTimerElapsed(object sender, ElapsedEventArgs e)
{
if(Monitor.TryEnter(_pollingLock);
{
//FtpHelper lists content of files in directory
...
foreach(var file in files)
{
using(var client = new WebClient())
{
client.Proxy = null;
using(var data = client.OpenRead(file.Uri)
{
//Use data stream to write file locally
...
}
}
//FtpHelper deletes the file
...
}
}
//Release the _pollingLock inside a finally
}
I would assume that a new connection is opened and closed for each file (unless .NET is doing something behind the scenes). If a file download had an issue, it would get a fresh retry on the next polling interval (in 3 sec). Why would a service restart make things work?
I've begun to suspect that the issue has something to do with caching (file or connection). Recently I tried going into Internet Explorer and clearing the cache. Approximately 30 sec or so later, all the files downloaded with no service restart. But, the next batch of files to arrive all got hung up again. I might try adding a line like this:
client.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
or try disabling KeepAlives, but I want to get some opinions before I start trying random stuff.
So: What is causing the occasional timeouts? Why does restarting the service work? Why did clearing the cache work?
Update
I made the cache policy and keep alive change mentioned above about two weeks ago. I just now got my first timeout since then. It appears to have improved frequency, but alas, it is still happening.
Update
As requested, this is how I am kicking off the Timer:
_pollingTimer.AutoReset = true;
_pollingTimer.Elapser += PollingTimerElapsed;
_pollingTimer.Interval = 10000;
_pollingTimer.Enabled = true;`
Looks like you are kicking off your processing using the System.Timers.Timer.Elapsed event.
One gotcha that I found is that if your Elapsed event takes longer to execute than the timer interval, your event can be called again from another thread before it has finished executing.
This is specifically mentioned in the docs:
If the SynchronizingObject property is null, the Elapsed event is
raised on a ThreadPool thread. If the processing of the Elapsed event
lasts longer than Interval, the event might be raised again on another
ThreadPool thread. In this situation, the event handler should be
reentrant.
Assuming you are indeed using a vanilla timer with AutoReset=true (its on by default), first thing to do would be address this potential issue. You can use a SynchronizingObject, alternatively you can do something like this:
//setup code
Timer myTimer = new Timer(30000);
myTimer.AutoReset = false;
....
//Elapsed handler
public void PollingTimerElapsed(object sender, ElapsedEventArgs e)
{
//do what you currently do
...
//when finished, kick off the timer again
myTimer.Start();
}
Either way, the main thing is to ensure that your code doesn't accidentally get called simultaneously by multiple threads - if that happens there's a good chance that occasionally you'll have one thread trying to download something from the site while another thread is simultaneously deleting the file.
The things that you mentioned e.g. it only happens occasionally, that normally file sizes are small, that its fixed by a restart, etc. would point me in the direction of this being the issue.
I'm using the GeoLocator class for a location aware app, I would like the position to be updated once every minute to save battery. I have set the ReportInverval attribute accordingly but the PositionChanged event is getting triggered much more frequently. What is wrong here?
App.Geolocator = new Geolocator();
App.Geolocator.DesiredAccuracy = PositionAccuracy.High;
App.Geolocator.MovementThreshold = 100;
App.Geolocator.ReportInterval = 1000*60; //report change every minute
App.Geolocator.PositionChanged += geolocator_PositionChanged;
That should give you a location every minute but the documentation does say:
If another application has requested more frequent updates, by specifying a smaller value for ReportInterval, your application may receive updates at a higher frequency than requested
Found out why it is not working. The solution was to not use MovementTreshold because it takes precedence over ReportInterval.
I am working with an ASP site which requires a "reminder" email to be sent out every x, y and z minutes. I have attempted to start a timer upon an event (like a button click or page load) but this proved to be unreliable as the timers would be disposed of when the server performed an automatic backup or when the aspx.cs file was updated.
My new idea is to have a timer constantly running (a check is performed on a page load which ensures its running) and, when it elapses, it checks to see if either x, y or z minutes have elapsed. So if y elapses, it needs to send out a "reminder" email and then restart y's timer.
void ParentTimer_Elapsed(object sender, ElapsedEventArgs e)
{
foreach(Timer childTimer in ChildTimerList)
{
if(childTimer.Enabled == false) // And therefore has elapsed
{
sendReminderEmail(childTimer);
childTimer = checkAndSetCorrectInterval(childTimer);
childTimer.AutoReset = false;
childTimer.Enabled = true;
}
}
}
The list ChildTimerList would obviously contain x, y and z.
Can anybody forsee me running into any problems with this, or are there any better ways to approach it? My perfect solution would be a timer running costantly which doesn't need to be started upon an event but I don't think this is possible with ASP.
Furthermore, where should I initialise my parent timer and childlist variables? In a class within the App_Code folder or, statically, in a code-behind aspx.cs page?
Thanks in advance.
EDIT:
Yes, I do mean ASP.NET... :)
I would probably implement this with a simple console application (responsible for sending e-mails) and Task Scheduler in Windows (responsible for running the application on a schedule). Keep it simple. And robust.
Edit: Provided that you are in control of the server - it will probably not be the best solution in a shared hosting environment where you're only allowed to run web apps.