• Prime Mover (unregistered)

    I appreciate the tortured irony in that last line.

    So Abraham goes to his boss. "Look at this, it's silly. Nobody does this. It should be ..."

    "Yes, yes, I know all that," says the boss. "That's been fixed. It's in the pipeline. It's waiting for a window of opportunity for it to be synergised into the test plan for eventual implementationing into our ...

    "Yes, well, when is that going to happen?"

    "Not immediately. It's been in the queue for the last 5 years, no reason to expect it'll happen in the foreseeable."

  • (nodebb)

    Actually, Windows' clock frequency isn't (just) at the control of the administrator or Windows version. Any application can request a higher frequency and Windows will run it at the highest frequency that is currently requested (there are extra complications, but that's the jist of how it works). That means that the reliability of the auto-sync is going to depend on what else the user happens to be doing on their system at the time.

  • Sole Purpose Of Visit (unregistered)

    Well, the second problem is in fact the first problem. The first problem wasn't really a problem at all. And a for the third problem, it isn't particularly relevant given the second problem. I mean, who is going to care (in this instance) about a drift of 18 ms per hour?

    As for the testing problem, it isn't a problem once the interval is fixed to be hourly. Obviously you'd do this by supplying the timer with a suitable interval. Obviously, in production, this would be configured to be hourly. Obviously, in testing, it would be configured to be rather less than hourly -- say, ten seconds?

    Unless of course part of your client estate happens to run on non-Babylonian time, or is in a relativistic time frame. I guess either of those cases would be quite difficult to test.

  • (nodebb)

    This is how I make sure I wake up in the morning: I look at the clock every minute, and mentally check the time - is it 6:00 yet? If so, get up, otherwise continue "sleeping".

  • my name is missing (unregistered)

    Perhaps better code would have resulted if the hourly rate was paid only when this timer fired.

  • (author) in reply to Mr. TA

    Ugh, as someone who naturally wakes up at random hours but refuses to get out of bed before 5AM, that is sadly so close to my process. "It's 3:45? Bah. It's 3:46? Bah."

  • David Jackson (unregistered) in reply to Mr. TA

    Oh! So it's not just me then!

  • Chris (unregistered)

    There's also the much more minor issue of how this implementation deals with leap seconds (could this cause two triggers in a row, or would it skip?) and daylight savings time (apparently Lord Howe Island leaps forward by half an hour).

    And Mr TA., my version also includes "OK it's now 6:30, so just half an hour late. Now it's 7:00, so an hour, but that's manageable. I'll just skip showering and breakfast. Um, OK, 7:30.."

  • Smithers (unregistered) in reply to Mr. TA

    Which, like this code, usually works. Until one morning you check the clock at 5:59:59, return to sleep for a minute, but get distracted by a sneeze at 6:00:58 and don't look at the clock until 6:01:00. "Not 6:00, better keep sleeping" and then you lose an entire day. Or half a day if it's a 12 hour clock.

  • WTFGuy (unregistered)

    There's also the subtle bug, or at least bad habit, of making 2 successive calls to Datetime.Now while intending to compare your values to a moment in time.

    As Yoda said of the future: "Hard to see. Always moving the future is.". Datetime.Now is also always moving; if you want to compare multiple properties to it, snag it into a temp and compare your properties to the non-moving temp.

    It happens that for the specific comparison of

    if (DateTime.Now.Second == 0 && DateTime.Now.Minute == 0)
    

    you'll never have a false positive or negative where the minutes will have moved after the seconds comparison has completed.

    But the bug can occur if your comparison was

    if (DateTime.Now.Second == 59 && DateTime.Now.Minute == 0)
    

    or

    if (DateTime.Now.Minute == 0 && DateTime.Now.Second == 0)
    

    It's a darn good bet that whoever wrote this code wasn't aware of this issue. IOW, they weren't taking advantage of a special case to avoid creating a temp; they were simply oblivious that the case existed, special or not.

  • (nodebb)
    1. The overhead is miniscule (yeah, not good design, but show me a REAL WORLD impact)
    2. Perhaps everyone doing it as close to the same time is a desired feature [which would be broken by arbitrary starting a 1 hour time.

    Now that being said, on a heavily loaded system, the timer could get backlogged, and NOT get processed while the second is still zero.....causing a missed update.

  • (nodebb) in reply to mallard

    "Any application can request a higher frequency and Windows will run it at the highest frequency that is currently requested" So if I request 1 terahertz........

  • (nodebb) in reply to Sole Purpose Of Visit

    I mean, who is going to care (in this instance) about a drift of 18 ms per hour?

    Well, if it drifts so that it triggers at 10:00:00 minus a few ms, then at 10:00:01 plus a few ms, and doesn't tick at all during 10:00:00, it will completely miss the ten o'clock autobackup.

  • (nodebb) in reply to Smithers

    That would be ideal actual, sleeping for half a day that is. Then I'll get up at 6pm ready to storm all the nightclubs in town.

  • Loren Pechtel (unregistered)

    In addition to the problems already mentioned, Windows doesn't even promise to call the routine every 1000ms. Rather, it promises to call the routine after at least 1000ms--no matter how far over it goes it's still within spec. The 1005ms mentioned in the article (which results in a 1 in 200 chance a sync is skipped) is simply the primary example.

  • Officer Johnny Holzkopf (unregistered) in reply to WTFGuy

    There might be an additional problem: The timer fires every second; the DateTime.Now check tests for min == 0 and sec == 0. This process seems to be fully "linear", so if the timer fires at 10:00:00, and the system schedules and executes some higher-priority work at that time, for example syncing a big file to disk, the next step could be delayed, i. e., the time check happens one second (or more seconds) later. It's now 10:00:01, the condition sec == 0 is no longer true (because it's == 1 now), and won't be true (for both min and sec) for the rest of the current hour. So it's "better luck next time" in an hour. Maybe a flag would be a better way of implementationing here, along with only one (in numbers: 1) call to DateTime.Now and a more reasonable checking frequency...

  • Brian Boorman (unregistered) in reply to WTFGuy

    Some languages would even allow the compiler to make the 2 calls to DateTime.now in either order.

  • Sole Purpose Of Visit (unregistered) in reply to Steve_The_Cynic

    At which point you simply adjust the time for the auto backup.

    Problem 4: We don't have the requirements here. For all we know, it's important that everything gets updated on the first second of every hour. Which means that, load be damned, you have to do this on the first second of every hour.

    Problem 5: We don't have the updated requirements here. For all we know, problem 4 was important, but is no longer important.

    Problem 6: Assuming problem 4, and assuming a load issue, the best we can do is to queue up client updates (parallelism entirely dependent upon machine factors, both for server(s) and client).

    Problem 7: This is a bit silly, much like problem 1. But just "hoping for the best" and allowing an hourly update from some time specified according to each client's starting point ... isn't necessarily going to work very well.

    Problem 8: [I]There may be one or more external platforms involved.[I] Again, no requirements visible. But let's stipulate that this system co-ordinates various other databases. And let's further stipulate that we have a Service Level requirement that all of those other databases upload to our system at, say, five seconds before the hour. (Not unreasonable for an Airline Res system.)

    Well, we've just screwed this up, haven't we? Either because of the time drift, or because of the server load, it's quite possible that our back end won't be fully updated before our front end starts propagating.

    So, in other words, the timer issue is not remotely interesting The design issue is more interesting. What the timer [I]should[I] do is to compare the current time state to the previous time state, and if an hour has genuinely passed, it should set some sort of semaphore. The update itself should wait on that semaphore, fire off (possibly with staggering or parallelisation to handle load issues) the update process, and reset the semaphore.

    Add in a state machine to handle back-end uploads before you hit the semaphore, and you're done.

  • Gimme a Minute (unregistered)

    I think that if you just kept some static variables around, you could check if currentHour != lastHour and then run the backup accordingly. That would allow you to always update as soon as possible (to within a second) despite any sort of delay, although it would probably be savvier to have it run once every 5 minutes or so. To deal with the application's being closed and restarted, you could query the main server for the last time you sent a backup or just default lastHour to the current hour on first run.

  • (nodebb)

    I think the correct solution here is to maintain a variable named nextDT. It's set to whatever date time you need the first iteration to execute at. Then, you set a timer to fire after nextDT minutes now. In the timer callback, you check if it's the correct time (to avoid shenanigans with sleep, computer time adjustments, etc.), and if so, execute. Either way, calculate nextDT again according to your schedule; and set the timer again.

    Addendum 2021-10-18 19:50: Minus now, not minutes now

  • ismo (unregistered) in reply to TheCPUWizard

    On a single user computer nothing major overhead. But imagine a server having multiple users like 50. Always imagine the scaling factor also, one should never write polling code, that was in the sixties when that was acceptable ( it still is in very special cases like device drivers when servicing interrupt and in handler it is known that second one shall happen very soon, making it feasible to spend some cycles polling device rather than return from handler and then handle new interrupt ( that takes also time))

  • (nodebb) in reply to Officer Johnny Holzkopf

    OFC the company I work for is doing that.

    IDK what's going on worldwide, I guess "leadership driven" companies are just the same everywhere. It is 5 years I am fighting to promote the idea "backups run 24 hours apart, not a specific second".

    I'm pretty sure most people a lot of people would be surprised by how many "0 minute 0 seconds" hours don't exist at runtime.

  • Scratched that itch (unregistered) in reply to mallard

    Actually, Windows' clock frequency isn't (just) at the control of the administrator or Windows version. Any application can request a higher frequency and Windows will run it at the highest frequency that is currently requested (there are extra complications, but that's the jist of how it works). That means that the reliability of the auto-sync is going to depend on what else the user happens to be doing on their system at the time.

    We ran into this at work, where it turned out that our code had serious performance issues if running at the default 15.625ms of timer resolution, but there usually was some other stuff running that lowered that number for it to kinda remedy that.

    With Windowsn 10 Update 2004, this mechanism was changed, and now every program gets its own timer period (see https://docs.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timebeginperiod)

  • MaxiTB (unregistered)

    First I can give a rational behind this pattern: It's code meant to be used with WinForm timer events. There's some reasons behind this way of doing polling events, it has mostly to do with messaging queuing, prioritizing and dropping of redundant Win32 messages.

    Secondly, System.Timers is obviously a net core class; so someone had the bright idea of applying a valid (but flawed, see below) pattern with something that doesn't have the same issue. Basically the "I can Java, so I know C#" issue but with "I know .net, so I know .net core". Pretty much a good give-away if the person next to you is absolute clueless and dangerous to work with.

    Thirdly, it's sloppy. DateTime.Now is a factory, it's a property, not a field. Guess whoever implemented this code doesn't know the difference. So it looks to me like someone applied a pattern that is outdated for over a decade at least and added their sloppy approach. Ouch.

    Usually my guess when something like that happens, I think "Must be a Java developer". In this case more "Must be a Java developer with medicore Stack Overflow skills". But honestly, hard to tell these days.

  • MaxiTB (unregistered) in reply to MaxiTB

    Ha, I forgot the main sloppiness at my third point, cause it's so obvious: It should be now.Hour instead of now.Second obviously.

  • t (unregistered) in reply to MaxiTB

    Nah, it just had to be implemented as quickly as possible, giving the Dev no time to actually look at any documentation of the timer class

  • Normski (unregistered)

    And, of course, you probably don't want to be doing "==" what you want to be doing is something along the lines of: if (elapsedTime >= 1 hour) then sync elapsedTime = 0 endif.

  • shabnam.f74 (unregistered)

    http://bkharim.com/

Leave a comment on “An Hourly Rate”

Log In or post as a guest

Replying to comment #:

« Return to Article