• supermagle (unregistered)

    Frist second!

  • Michael P (unregistered)

    TRWTF is that Remy has never run into cases where "sleep X time between execution" adds up over time to something other than "run once every X time". Between the inherent runtime of the work and OS scheduling jitter, sleeping for X between work is a poor way of controlling how often work happens. This is exactly why most OSes have some variety of interval timers.

  • blurp (unregistered)

    The real what the fuck is rethrowing the exception like that, in c# you can do throw; so you keep the stacktrace information intact, not sure what the syntax is for that in VB.NET. Even if you would get a new log entry the exception will still be useless because of the stacktrace points to the wrong location.

  • Vault_Dweller (unregistered)

    When I saw the "aboutnow" variable I got Rockafeller Skank stuck in my head.

  • Lune (unregistered) in reply to Michael P

    Of course he has seen the problem of drift. That's why he said, "we could easily calculate that sleep time with reasonable accuracy if we actually looked at the seconds portion of the current time." In other words, observe the drift and reduce the next sleep time accordingly. That is a perfectly reasonable way to avoid that issue, though of course using the language facility for intervals is better.

  • (nodebb) in reply to blurp

    not sure what the syntax is for that in VB.NET

    The syntax in VB.Net is:

    Throw
    
    It's exactly the same WTF in VB as it is in C# and the solution is exactly the same.
    
  • (nodebb) in reply to Michael P

    sleeping for X between work is a poor way of controlling how often work happens

    Yup. This also properly handles daylight savings time, schedule changes while running, and clock adjustments.

  • Anon (unregistered)

    What people have against schedulers like Windows Task Schedulers?

  • WTFGuy (unregistered)

    @Anon: Nothing wrong with Windows Task Scheduler if you're trying to launch an exe on an interval.

    But if the thing to be launched periodically is a thread or process within a larger exe, or true Windows Service, WTS is totally inapplicable.

    The code strongly implies the latter use case, not the former.

  • Jay (unregistered)

    If it sleeps for more than one minute or more than half a minute but less than a whole minute, the process could miss it's window to run and could take 24 hours until it gets a chance to run again if i remember how sleep works. I have to assume that DateTime.Now.AddSeconds(5).ToString("HH:mm") will increment the minutes by 1, but I don't happen to have the documentation handy to show that that is the expected behavior. If not, then the process could fail at an additional point if my aboutnowOld = current HH:mm.

  • Jay (unregistered)

    I missed something. The loop always updates aboutnowOld. So the later case will miss the run if aboutnow = aboutnowOld but aboutnowOld will always get incremented. As long as it's by more than one minute, the loop will not fail EVERY time the window is hit.

  • (nodebb) in reply to Anon

    What people have against schedulers like Windows Task Schedulers?

    Notification and logging are atrocious.

  • Vilx- (unregistered)

    Wait a minute, no easy reader version? :'(

  • i be guest (unregistered)

    there's no ending punctuation

    i almost expected "and..." after the final "sentence"

    The developer who wrote this saw the problem of "execute this code once every polling interval"

  • Steve (unregistered) in reply to WTFGuy

    But if you're willing to compartmentalise your code, and get creative in Powershell there's very little that you can't fire from a scheduled task. Certainly a whole lot more reliable than rolling your own scheduler as above

  • (nodebb) in reply to Steve

    Ahh.. the "anti-DevOps" approach.

  • Naomi (unregistered) in reply to Steve

    But at what cost? The cost of writing PowersHell, of course. I wouldn't wish that on my country's wannabe dictator.

  • ooOOooGa (unregistered)

    In case anyone is coming here looking for good ways of handling this type of problem and finds the idea of firing off a process from the OS task scheduler (of whatever variety), I'll put in my lessons learned from the school of hard knocks.

    If you are going to fire off a process once per minute from the task scheduler (Windows Task Scheduler, cron, systemd timers, etc...) be sure to either: 1) Make absolutely, positively, 100% sure that the process will finish in less than a minute. 2) Design the process so that multiple instances can be running at the same time without stepping on each other's toes. 3) Put in some form of locking to prevent multiple instances from being started.

    And never, ever, EVER rely on option #1.

  • tigerw (unregistered)

    The article says

    The developer who wrote this saw the problem of "execute this code once every polling interval"

    and then just ends; is anyone else seeing this or just me?

  • (nodebb) in reply to WTFGuy

    @Anon: Nothing wrong with Windows Task Scheduler if you're trying to launch an exe on an interval. But if the thing to be launched periodically is a thread or process within a larger exe, or true Windows Service, WTS is totally inapplicable.

    Is there a native call along the lines of SleepUntilWindowsEvent(EventID)? IIRC there's one use case at the current day job where we use a custom EventID rather than a fixed schedule, but I'd have to double-check whether WTS was on the sending or receiving end of that case.

  • Anon (unregistered)

    And why it NEED to be a service?

    Last time I had to execute something periodically on a Windows Service (and this had to be a service because it also received request from other sources) I did a small exe that issued a request to the service and schedulled the exe instead of reinventing the wheel on the service, it was many years ago on Windows 2003, I know starting with Vista MS added APIs to schedule thing programatically.

    Its much safer then creating your own scheduler, for example, besides all the WTF the one in the article today have a bug nobody commented yet, if the loop doesn't fire the action for 1 minute for whatever reason (like, it is in a halted VM) it will never fire again until restart.

  • (nodebb)

    Hmmmmm...looks like this should work aboutNever.

  • Prime Mover (unregistered)

    If this is supposed to be doing what I think it's supposed to be doing, then IMO a better approach would be to write it as a simple program that runs once, then kicked off at a regular interval by a scheduler.

  • Your Mammas name (unregistered)

    The WTF is the first sentence, everything else can be ignored - you don't implement a new service, get it deployed, and then leave for vacation until it's stable.

  • Fab (unregistered)

    Among other point, he should learn about System.Threading.Timer

  • (nodebb) in reply to Anon

    Its much safer then creating your own scheduler

    Building a Windows Service in C# or VB.Net is really easy. You really have two choices:

    1. Build a service and get everything else you want for free.
    2. Use a canned scheduler and deal with monitoring, error handling, logging, etc.. at the payload level.

    Using a commercial scheduler is really buying the easy solution and making the hard one harder. I have had much more success working on the easy problem (a loop) and building rich integrations into our monitoring infrastructure.

    I have inherited the worst of both worlds. We have a large number of programs that launch from a scheduler (AutoMate), and they are all GUI programs that use message boxes for error reporting. To make things worse, the automation is so flaky that the server is rebooted every night. So, now it's someone's job to remote into the server and look for errors between 2:00 and 4:00 every morning.

    Nowadays, containers are a viable alternative to services. However, a Windows Service written in C# with minimal dependencies is pretty trivial to deploy and manage - making containers look like killing flies with a sledgehammer. If you monitoring is already built around a particular containerization technology, then that's certainly a better way for you.

  • Sole Purpose Of Visit (unregistered)

    Well, yes, all that.

    But what you actually want is Separation of Concerns. You have a class that acts to count off the seconds, and store timing events. It will be a singleton. It will export a single method (C# version, for relative clarity to non VB.Net users):

    public void AddTimeoutEvent(int seconds, Action action, long nanoseconds = 1000000000, bool repeat = false)
    {
        // Find current time in seconds after epoch.  Calculate "timeout" using nanoseconds.
        // Add (timeout, action, nanoseconds, repeat) into sorted class list.
    }
    

    That's pretty much it. The class just sits there as a timer, pulsing on the interval of a second, and fires the actions off as required. (In VB.Net or C#.Net, you may need to add InvokeRequired and BeginInvoke if you're dealing with the GUI, in which case you need to pass the control as a parameter. But this is supposedly a Windows Service, so ... no.)

    I rather think that, if you have a problem with an OS seconds-long lag on a machine whose hardware counts in nanoseconds, then you have a much bigger problem than you think you have. And if you do? Heck. Store the original start time in the code that does the action. Don't use repeat = true. Calculate the offset between your original start time and the "action" time. Figure out the next "nanoseconds." Call AddTimeoutEvent again. Rinse, wash, repeat. This is not difficult. Real-time programmers do it all the time ... well, we used to, in the 1980s, but now we have libraries to do it for us.

    Every single bit of the code in the OP screams out total incompetence. There's no point in analysing the individual stupidities.

    It's just a ridiculous misconception of how timers work. In any language whatsoever.

  • MiserableOldGit (unregistered)
    Every single bit of the code in the OP screams out total incompetence. There's no point in analysing the individual stupidities.

    It's just a ridiculous misconception of how timers work. In any language whatsoever.

    Or perhaps how time itself works! Looks like two separate chunks of copypasta from some "support" forum, munged together, so the result is worth less than the sum of the parts, and none of it was up to much to start with. I inherited something like this once, except there were hundreds of lines of it surrounding some ill-conceived expensive third party file transfer software. This then was a morning every day for some one (ie: me) to go digging through logs and error reports to find out which stuff hadn't happened right (or at all) and go execute it manually, 24 or 48 hours (or longer) after the fact.

    I replaced it with a few lines of scripting, which did then need some fleshing out, but it enabled me to identify and resolve all the actual problems so the damn stuff just worked. I then spent my time working my way through the backlog of actual issues and change requests.

    A corporate merger then came along and everything was to be rolled into one of the MS Dynamics horrorshows. I left them to it, apparently the outfit was then sold off to this lovely fluffy venture capitalists KKR, so I guess things must have gone well.

  • Chris (unregistered) in reply to Jay

    I have to assume that DateTime.Now.AddSeconds(5).ToString("HH:mm") will increment the minutes by 1, but I don't happen to have the documentation handy to show that that is the expected behavior.

    Wait, what? Getting the time, and adding 5 seconds, should be expected to increment the minutes by 1?! Even if it's due to showing the time in HH:MM, that, gah, why would that ever?! Now my head won't work for the rest of the day, thanks.

  • Yazeran (unregistered) in reply to ooOOooGa

    If you are going to fire off a process once per minute from the task scheduler (Windows Task Scheduler, cron, systemd timers, etc...) be sure to either: 1) Make absolutely, positively, 100% sure that the process will finish in less than a minute. 2) Design the process so that multiple instances can be running at the same time without stepping on each other's toes. 3) Put in some form of locking to prevent multiple instances from being started.

    And never, ever, EVER rely on option #1.

    We use approach 3, I always put i a semafore test at the start of cron job scripts which test if the semafore is set by a previous invocation and exits if so. If not it set is and do i's business and removes it just before exit. That way at max 2 is running at the same time (one doing work, and potentially one checking the semafore, although you have to be lucky to catch one of those with ps)

  • doubtingposter (unregistered)

    This was a bit of bad narrative: The top left me trying to find out why there would be no entry in the logging, but even though the exception handling is a bit clumsy, it should work for logging the exception.

    The only way I see this exception handling pattern make sense is if they have some blanket catch statements in the snip somewhere, and store the exception in the field. That way it can have a single point of logging. Of course, then it'll rethrow an exception that's possibly grown stale for hours, but who cares about that really.

Leave a comment on “Wait a Minute”

Log In or post as a guest

Replying to comment #:

« Return to Article