In my Windows Phone Applicarion I need to implement logic to start some Method every 20 days, how can I implement this?
public void Method()
{
//some logic
}
Update
For example I can fix the first start of some method, then every start of application I will fix the current date time and them calculate the differens, and if the difference between the last and first sstart of some method will be more than 30 days I will start Method(). So how can I calculate the difference (days)?
Not easily!
The best fit for this is to use a Scheduled Agent - but this runs ever 30 minutes approximately - so you would need to keep track of the last run time and act accordingly.
The other issue with this is that if the app that is associated with the scheduled task is not run at least ever 14 days the task is disabled.
HTH,
Rupert.
So you want to know if it's 20 (or more?) days since you last performed an action in your app.
Let's assume that you save the date to calculate from as a DateTime called savedDate. (I'm assuming you can put this in and retrieve from IsolatedStorage without issue.)
Then you can just do a simple test against the current date:
if (saveddate.Date.AddDays(20) <= DateTime.UtcNow.Date)
{
// Do your every 20 days action here
// and then probably reset savedDate to the current date?
}
What about a push notification. You let the server take care of this. When the time is ready it sends a notification to the phone which does things accordingly.
Edit:
To find the difference you can do something like this
TimeSpan span = endTime.Subtract(startTime);
if(span.Days >= 20)
Method();
You could store the last time the method was ran in Isolated Storage, and then use the Scheduled Agent to run every 30min:
if (DateTime.Now.Subtract(LastTimeRanFromIsolatedStorage) > TimeSpan.FromDays(20))
{
Method();
}
Related
I am able to log a fortnightly job using Hangfire,
if (vm.ReportInterval == 14)
{
reportFrequency = Cron.DayInterval(14);
}
This is working and doing it what it is supposed to do.
But What I want is to start the job on a particular date and then repeat every 14 days.
Essentially , need to pass a second parameter to cron.DayInterval.
Example(This is not supported):
if (vm.ReportInterval == 14)
{
reportFrequency = Cron.DayInterval(14,new DateTime(2018,17,05));
}
I looked at Cron class and it does not have a supported method to do so:
Is there another class on Hangfire to do the job?
The other way is to do a weekly job and then
Pass custom parameters
Check in method if needs to be executed (by date diff from last execution)
Skip if Date diff is not 14 days
But I really do not want to go that way if there is a better approach.
You need to create a RecurringJob that looks like this:
RecurringJob.AddOrUpdate<IExportService>(
"Export data",
x => x.ExportToEmail(),
"0 0 0 1/14 * ? *");
The important bit is the last parameter wich is a cron expression that says:
Run this job At 00:00:00am, every 14 days starting on the 1st, every month
If you want to create another cron expression I would suggest this online generator:
https://www.freeformatter.com/cron-expression-generator-quartz.html
I've been given a task to write a program to count how many page views are requested from our site. My current approach is to get data from google analytics Real Time API, which works to my suprise.
My problem is that to get pageviews every minute I need to poll data from google API twice (cause it returns sum of last 29 minutes + a value from a timer that resets every minute). After I set up 'the point of reset', lets just say, on a 55th second every minute, I poll data on 56th and later on at 53th second, which gives me relatively good estimation of new users / page views requested.
So this is my current approach:
static System.Timers.Timer myTimer = new System.Timers.Timer();
myTimer.AutoReset = false;
myTimer.Interval = interval();
myTimer.Elapsed += myTimer_Elapsed2;
myTimer.Start();
static double interval()
{
return 1000 - DateTime.Now.Millisecond;
}
static void myTimer_Elapsed2(object sender, System.Timers.ElapsedEventArgs e)
{
if (DateTime.Now.Second == (resetPoint.Second - 1) % 60 && warden)
{
DoStuff(); //mostly inserting google API data to database
}
else if (DateTime.Now.Second == (resetPoint.Second + 1) % 60) //so we dont get riddiculous 60 and above
{
//I get some data here, to later use it in DoStuff - mostly to calculate the gap between later
}
myTimer.Interval = interval(); //Because DoStuff() takes about 0.5 sec to execute, i need to recalibrate
myTimer.Start();
}
And it works really well, until it stops after about 2 hours, for now I have no idea why (program runs, just timer doesn't do its work anymore).
How do I make it stable for long periods of time? Best case scenario would be to run it for months without intervention.
# I edited to give a better sense what I'm actually doing
#END CREDITS
I ended up using two timers, each running in a one minute circle. And a database writing sometimes crashed and I didn't handle the corresponding exception properly. Log told me that google API functions from time to time tend to retrieve data a bit longer, which led to multiple Threading.Event calls and made my database data handling throw an exception hence stopping the timer.
I tried to use Quartz approach but its lack of human-friendly howto made me abandon this library.
You should really look into using Quartz.net for scheduling events on a reliable basis. Using a timer for scheduling is asking for stuff like race conditions, event skips and database deadlocks.
http://www.quartz-scheduler.net/ allows you to schedule events at precise intervals, independant of when your code starts or stops.
An example on how you use it: This will build a trigger that will fire at the top of the next hour, then repeat every 2 hours, forever:
trigger = TriggerBuilder.Create()
.WithIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
.StartAt(DateBuilder.EvenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
.WithSimpleSchedule(x => x
.WithIntervalInHours(2)
.RepeatForever())
// note that in this example, 'forJob(..)' is not called
// - which is valid if the trigger is passed to the scheduler along with the job
.Build();
scheduler.scheduleJob(trigger, job);
http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/simpletriggers.html has a few examples. I really URGE you to use it, since it will severely simplify development.
The .NET timer is reliable. That is, it won't just stop working randomly for no apparent reason.
Most likely, something in your timer event handler is throwing an exception, which is not surfaced because System.Timers.Timer squashes exceptions. As the documentation states:
The Timer component catches and suppresses all exceptions thrown by event handlers for the Elapsed event. This behavior is subject to change in future releases of the .NET Framework.
That bit about the behavior being "subject to change" has been there since at least .NET 2.0.
What I think is happening is that the timer calls your event handler. The event handler or one of the methods it calls throws an exception, and the timer just drops it on the floor because you don't handle it.
You need to put an exception handler in your myTimer_Elapsed2 method so that you can at least log any exceptions that crop up. With the information provided from the exception log, you can probably identify what the problem is.
Better yet, stop using System.Timers.Timer. Use System.Threading.Timer instead.
Finally, there's no way that your code as written will reliably give you a timer tick at exactly 55 seconds past the minute, every minute. The timer isn't exact. It will be off by a few milliseconds each minute. Over time, it's going to start ticking at 54 seconds (or maybe 56), and then 53 (or 57), etc. If you really need this to tick reliably at 55 seconds past the minute, then you'll need to reset the timer after every minute, taking into account the current time.
I suspect that your need to check every minute at exactly the 55 second mark is overkill. Just set your timer to tick every minute, and then determine the exact elapsed time since the last tick. So one "minute" might be 61 or 62 seconds, and another might be 58 or 59 seconds. If you store the number of requests and the elapsed time, subsequent processing can smooth the bumps and give you a reliable requests-per-minute number. Trying to gather the data on exact one-minute boundaries is going to be exceedingly difficult, if even possible with a non-real-time operating system like Windows.
I need to capture the time taken between two button press of ten users.
I am doing like this with StopWatch.
Stopwatch stopwatch1;
Stopwatch stopwatch2;
........ Like this ten stop watches.
private void Start_Action1()
{
stopwatch1 = new Stopwatch();
stopwatch1.Start();
}
private void Stop_Action1()
{
stopwatch1.Stop();
txtTimeForAction1.Text = stopwatch.Elapsed.ToString();
}
Same code for 10 StopWatches.
NOTE: All the users will do this START-STOP action continuously. I need to record time-elapsed for each cycle separately. I am using in desktop application. All the users will use the same application.
Using 10 Stopwatch is good practice?? Is there any better way than this?
You could keep track of the starting times for every user, use one stopwatch and don't stop it after the stop action is called by one user, only when they have all stopped. I don't know if it's better practice, but it is a different way to do it.
Personally, I'd give each "user" a DateTime (StartTime) and then when the event has finished (So E.g. Key_Up) You can get the Elapsed time with:
DateTime elapsedTime = DateTime.Now - StartTime.
then use elapsedTime.Seconds or .Minutes etc. and even use elpasedTime.ToString("hh:mm:ss") to get a nicely formatted string.
I see no reason why not using stop watches. But instead of defining ten stop watches you should save them in an array or in a dictionary where each StopWatch is associated with a user.
I was thinking of changing system's local time to server's time and then use it but I bet there are other ways to do this. I've been trying to find something like a clock in c#, but couldnt find anything. I'm receiving server's time in a DateTime format.
edit:
I need my application to use while working same time server does. I just want to get server's time once and after that, make my application work in a while loop using the time I've obtained from the server. There might be a difference between my system's time and server's time (even 5 seconds) and that's why I want to do this.
It's not entirely clear what you mean, but you could certainly create your own IClock interface which you'd use everywhere in code, and then write an implementation of that which is regularly synchronized with your server (or with NTP).
My Noda Time project already uses the idea of an injectable clock - not for synchronization purposes, but for testability. (A time service is basically a dependency.) Basically the idea is workable :) You may well not find anything which already does this, but it shouldn't be too hard to write. You'll want to think about how to adjust time though - for example, if the server time gets ahead of your "last server time + local time measurements" you may want to slew it gradually rather than having a discrete jump.
This is always assuming you do want it to be local to your application, of course. Another alternative (which may well not be appropriate, depending on your context) is to require that the host runs a time synchronization client (I believe Windows does by default these days) and simply start failing if the difference between your server and the client gets too large. (It's never going to be exactly in sync anyway, or at least not for long - you'll need to allow for some leeway.)
The answer #JonSkeet's provided to synch the times looks good, I just wanted to point out some things.
As #Alexei already said, users require admin privileges to be able to change their local time (in Windows as least), but there may also be other issues that can cause the time to be out of synch (bad internet connection, hacks etc.). This means there is no guarantee that the client time is indeed the same as the server time, so you will at least need to check the time the request was received serverside anyway. Plus there might also be a usability issue at hand here, would I want an application to be able change the time of my own local machine? Hell no.
To sum things up:
Check the time of the request serverside at least
Don't change the time of the client machine but show some kind of indicator in your application
How to handle the indicator in your application can be done in various ways.
Show a clock in your application (your initial idea) that is periodically synched with the server
Show some kind of countdown ("you can submit after x seconds.."), push a resetCountdown request to the clients when a request is received.
Enable a 'send button' or what ever you have, this would work kind of similar to the countdown.
Just remember, it's nearly impossible validate a request such as this clientside. So you have to build in some checks serverside!
I actually wanted to write a comment but it got kind of long.. :)
Okay a bit of necromancy as this is 6 years old, but had to deal with a similar problem for a network game.
Employed a technique I referred to as "marco-polo" for reasons that will be obvious soon. It requires the two clocks to be able to exchange messages, and its accuracy is dependent on how fast they can do that.
Disclaimer: I am fairly certain I am not the first to do this, and that this is the most rudimentary way to synchronize two clocks. Still I didn't find a documented way of doing so.
At Clock B (The clock we're trying to synchronize) we do the following ::
// Log the timestamp
localTime_Marco_Send = DateTime.UtcNow;
// Send that to clock A
SendSyncRequest();
// Wait for an answer
Sleep(..);
At Clock A (the reference clock) we have the following handler ::
// This is triggered by SendSyncRequest
OnReceiveSyncRequest()
{
// We received "Marco" - Send "Polo"
SendSyncReply(DateTime.UtcNow);
}
And back at Clock B ::
// This is triggered by SendSyncReply
OnReceiveSyncReply(DateTime remoteHalfTime)
{
// Log the time we received it
DateTime localTime_Polo_Receive = DateTime.UtcNow;
// The remote time is somewhere between the two local times
// On average, it will be in the middle of the two
DateTime localHalfTime = localTime_Marco_Send +
(localTime_Polo_Receive - localTime_Marco_Send) / 2;
// As a result, the estimated dT from A to B is
TimeSpan estimatedDT_A_B = localHalfTime - remoteHalfTime;
}
As a result we now have access to a nifty TimeSpan we can subtract from our current local time to estimate the remote time
DateTime estimatedRemoteTime = DateTime.UtcNow - estimatedDT_A_B;
The accuracy of this estimate is subject to the Round Trip Time of send-receive-send-receive, and you should also account for Clock drift (you should be doing this more than once):
Round-trip-time. If it were instant, you'd have the exact dT. If it takes 1 second to come and return, you don't know if the delay was on the sending or the receiving. As a result, your error is 0 < e < RTT, and on average will be RTT/2. If you know send (or receive) takes more than the other, use that to your advantage - the time you received is not the half-time, but is shifted relatively to how long each leg takes
Clock drift. CPU clocks drift, maybe 1s per day. So poll again once potential drift may play an important role.
Your server should always save the time in UTC mode.
You save time in UTC like this in the server:
DateTime utcTime = new DateTime(0, DateTimeKind.Utc);
or:
DateTime utcTimeNow = DateTime.UtcNow;
In the client, when you get the time which is stored in utc you can sonvert it to local time like this:
public DateTime ToLocalTime(DateTime utcTime)
{
//Assumes that even if utcTime kind is no properly deifned it is indeed UTC time
DateTime serverTime= new DateTime(utcTime.Ticks, DateTimeKind.Utc);
return TimeZoneInfo.ConvertTimeFromUtc(serverTime, m_localTimeZone);
}
If You want to change your local time zone , here is a code example on how to read time zone to use from config:
string localTimeZoneId = sysParamsHelper.ReadString(LOCAL_TIME_ZONE_ID_KEY, LOCAL_TIME_ZONE_DEFAULT_ID);
ReadOnlyCollection<TimeZoneInfo> timeZones = TimeZoneInfo.GetSystemTimeZones();
foreach (TimeZoneInfo timeZoneInfo in timeZones)
{
if(timeZoneInfo.Id.Equals(localTimeZoneId))
{
m_localTimeZone = timeZoneInfo;
break;
}
}
if (m_localTimeZone == null)
{
m_logger.Error(LogTopicEnum.AMR, "Could not find time zone with id: " + localTimeZoneId + " . will use default time zone (UTC).");
m_localTimeZone = TimeZoneInfo.Utc;
}
Writing a C# app to run some scheduled tasks, all I really need is something to continuously monitor the date and time, and call a function once, on the 28th of each month, and then go back to waiting patiently for the 28th of the next month to come around.
I guess it will be using System.Threading.Thread.Sleep() in some way, but as for the specific conditions under which it should run, and how to prevent it from running multiple times on the date in question, I'm not sure...
Any help greatly appreciated :)
You can set up a Windows Scheduled Task to run your console app on the 28th of every month.
It's simple, easy and light on the server's resources since your app wouldn't take up any resources between runs.
If the PC is down, you can also tick the option: "Run task as soon as possible after a scheduled start is missed."
There are a huge number of options for you to customize how your task is run, such as:
Only run when a user is logged on.
Specify program parameters.
Start the task only if the computer is on AC power.
Start the task only if the following network connection is available.
Not all option may be available in all versions of Windows.
You can use loop which runs each second and checks for the date, and at specified date acts and waits for the next month. You will use System.Threading.Thread.Sleep() to put it on wait for 1 second.
You can wait for the next date by having last date traacked and calculating next date by adding to it 1 monnth.
DateTime? counter = null;
while (1 = 1)
{
if (DateTime.Now.Day == 28 && (!counter.HasValue || counter.Value.Date < DateTime.Now.Date ))
{
counter = DateTime.Now;
DoSomething();
}
Thread.Sleep(1000);
};