This seems...not right



  • I need to add something to the server (written in python) so that a method gets called at a certain time (required precision +/- a minute, say) to kick off an event, usually days in advance. Events will be read in from a file at startup and scheduled to run on the off chance the server hasn't crashed in the meantime.

    The simplest thing I thought of was just

    t=threading.Timer(<however many hundreds of thousands of seconds from now until 8 PM on saturday>, <method>)
    t.daemon=True
    t.start()
    

    but I'm concerned about precision. Alternatively I could create a thread to loop infinitely and check the time every 30 seconds, but that seems ugly and like more work than I should need to do.

    wat do?


  • Discourse touched me in a no-no place

    crontab?



  • Hmm, well the task really only depends on data internal to the server program; I don't think I could make it standalone so it could run externally.

    Essentially it's a chat server that functions as a matchmaking tool for online gaming, and at time X on day Y I want to broadcast an invitation to everyone online to join a tournament that the server will be running. If I scheduled something externally to signal it I'd still end up spinning watching for the signal anyway.

    (Also, it's someone else's project and I'm hoping the lighter my changes are the more likely he is to pull my stuff into the main release)



  • Still seems like an ideal task for crontab/Task Scheduler. Add a periodic job at whatever granularity you want to support (daily, hourly, 15-minutes), and then have it check the database for any unfulfilled notifications in the past, send them off, and then remove them from the database.

    Your users then can schedule a notification for 8:07pm on Saturday, and when the task runs at 8:15pm (or whatever granularity you set up to support), the notification goes out. Obviously, the best way to set up the front end would be to match the granularity of the back end (so users could choose 8:00pm or 8:15pm in a 15-minute granularity scenario, but not 8:07pm).



  • Can you tell the chat server to send the message from some other program on the machine it's running on?

    crontab → a short python script or whatever → server sends broadcast message



  • Although I will admit, the import scheduling process was basically

    while [[ $(date +%s) -lt '[unix timestamp of when the import should start]' ]]; do sleep 10; done; '[start import]' 2>&1 | tee >(xz -zc > import.log.xz)
    

    in a screen on the droplet that has an SSH session open to the docker instance.



  • There are at least a couple of Python modules matching crontab...


  • Discourse touched me in a no-no place

    @dookdook said:

    Alternatively I could create a thread to loop infinitely and check the time every 30 seconds, but that seems ugly and like more work than I should need to do.

    That's effectively how cron (and other cron-alike schedulers) works. Yes, it's possible to use a wait until the next time something is scheduled to run, but it needs to be an interruptable wait so that you can add other things to the queue, etc. Since you're talking about scheduling stuff days in advance, the queue really ought to be kept in a database (or file) so that service restarts don't cause it to be forgotten.

    Surely someone's already solved this so you don't have to.



  • @dookdook said:

    Alternatively I could create a thread to loop infinitely and check the time every 30 seconds, but that seems ugly and like more work than I should need to do.

    I'm going to make a guess and say you're not using a Windows server where you have access to Windows Scheduled Tasks... because that would be perfect for something like this. Make the OS do the work.

    EDIT: my understanding of Crontab is that it does not "catch-up" if the service/computer reboots. Any events missed during the restart will never be run. So that doesn't really work here.

    I think you just need to write a Python class/service that:

    1. Sleeps a worker thread until the next scheduled event (in C#, you'd use a Timer class, so it's interruptable-- not sure what the Python equivalent is)
    2. Can accept incoming scheduled events
    3. Persists the data to some data storage device (whatever DB the application is already using-- probably don't want to use the filesystem unless you have no other choice.)

    Note you have TWO classes/threads here: one that does the actual sleeping and processing of events (the "waiter"), and one that handles other event-management events (primarily adding new events to the DB). The "handler" needs to be able to interrupt the "waiter". Or, if Python has no Timer-equivalent, just kill-off the "waiter" and start a new one.

    That'd be maybe 100-150 lines in C#.


  • Winner of the 2016 Presidential Election

    @blakeyrat said:

    EDIT: my understanding of Crontab is that it does not "catch-up" if the service/computer reboots. Any events missed during the restart will never be run. So that doesn't really work here.

    While this might be true (didn't check) it's inconsequential in this particular case. Late notifications would be useless anyway.

    As for the rest, I agree. And I'd be surprised if there's no python library that handles this sanely.

    With a service (again, assuming there's a sane way to do that with python) another option is to write it so that it can receive commands from the system while it's running. That way it would be possible to put something like service --send-notifications into crontab which prompts the service to check it's DB (or wherever the events are stored) and send out any notifications that should be sent at the moment.



  • @Onyx said:

    Late notifications would be useless anyway.

    If your computer is restarting the service, and let's say that takes (at the WORST case 15 seconds), and it just happens to do it at a time when an event is set to trigger, the notification will be at most 15 seconds late. That's probably 10 seconds less than the average email delivery lag anyway.

    Is that really "useless anyway"? Maybe for a machine-to-machine system, but you're notifying humans, right? And it would suck if someone missed a tournament due to that.

    @Onyx said:

    And I'd be surprised if there's no python library that handles this sanely.

    From my experience of Python's libraries, I'd be more surprised if there's one. I'm sure there's 47 half-complete ones.


  • Winner of the 2016 Presidential Election

    @blakeyrat said:

    If your computer is restarting the service, and let's say that takes (at the WORST case 15 seconds), and it just happens to do it at a time when an event is set to trigger, the notification will be at most 15 seconds late. That's probably 10 seconds less than the average email delivery lag anyway.

    I didn't consider the reboot scenario. That's valid.

    Quick search would seem to indicate anacron can help with that though:

    (how the hell do you onebox an answer?)



  • @Onyx said:

    (how the hell do you onebox an answer?)

    From my limited testing, I don't think that you can, other than copy/paste.

    When your computer is shut down (or the cron daemon is otherwise not running), cron jobs will not be started.
    ­
    If you have jobs that you would like to run after the fact during those times when the computer is shut down, use anacron. Installed by default, see "man anacron", "man anacrontab", or the file /etc/anacrontab for more info...



  • This does strike me as something you would typically do with a bot, external to the server process. The server likely does not need to listen to it any different than any other client, except the bot has 'broadcast' permissions, which normal users do not have (but the admin likely already has).

    As mentioned by others there are various standard scheduling mechanisms. cron allows periodic jobs to run at a specific time. anacron is an alternative, to periodically schedule tasks on a system that is not always up. It does not allow specifying a time-of-day. at allows scheduling of one-off jobs.

    For this purpose I'd recommend cron; you do not want to send with significant delay, and short outages of the chat server can be handled with connect retries in the bot.



  • @blakeyrat said:

    EDIT: my understanding of Crontab is that it does not "catch-up" if the service/computer reboots. Any events missed during the restart will never be run. So that doesn't really work here.

    At boot, cron will run any tasks scheduled in the last 4 hours, with more than 4 hours between runs, that did not get run. Anything before that gets dropped.

       Special considerations exist when the clock is changed by less than 3 hours, for example at the beginning and
    
       end  of  daylight  savings  time. If the time has moved forwards, those jobs which would have run in the time
       that was skipped will be run soon after the change.  Conversely, if the time has moved backwards by less than
       3 hours, those jobs that fall into the repeated time will not be re-run.
    
       Clock changes of more than 3 hours are considered to be corrections to the clock, and the new  time  is  used
    
       immediately.
    

    However, we're talking about "every 15 minutes, check the database", and it'll just 'catch up' with everything in the database at the next 15-minute run.


  • Winner of the 2016 Presidential Election

    @Onyx said:

    Quick search would seem to indicate anacronsystemd timers can help with that though

    FTFY

    ½ :trollface:


  • Winner of the 2016 Presidential Election

    Do they have to replace fucking everything with they shitty half-baked implementations? Really?



  • I don't think it's a half-baked implementation, because timers can have Requires, Conflicts, Before, After, PartOf, JobTimeoutSec, ConditionPathExists, ConditionVirtualization, etc., and can trigger a service with PrivateDevices, PrivateNetwork, User, Group, OOMScoreAdjust, and all the other E-Z-Environment features of systemd.

    And you can always shell out. You'll just have less shells running in the end, decreasing your "first user PID".

    Also I just read about Upstart's SIGSTOP readiness signal and that's fucking retarded, really?


  • Winner of the 2016 Presidential Election

    Honestly, I didn't poke around it so much. I just remember reading/hearing about them needlessly replacing some stuff with the end result being that it's not nearly as good as it used to be. I believe someone mentioned something about DHCP?

    It's word of mouth so it might be all bullshit, but replacing stuff seems to be a trend with systemd, and I'm not sure all of it is really justified.



  • @Onyx said:

    It's word of mouth so it might be all bullshit, but replacing stuff seems to be a trend with systemd, and I'm not sure all of it is really justified.

    Yeah, probably. I can't figure out which parts, though.

    Though they did drop their readahead implementation...


  • Winner of the 2016 Presidential Election

    @Onyx said:

    Do they have to replace fucking everything with they shitty half-baked implementations? Really?

    Actually, I think replacing cron is one of the more sensible things they've done. I can't think of a single reason why the same program that manages system services anyway shouldn't also manage periodic processes.



  • It's not just a matter of broadcasting once, the server will handle the execution of the event afterwards as well, which could take hours. If I set up a separate program to handle everything, there'd need to be realtime synching of client lists between the two, which currently are only stored internally to the server script, and that sounds awful.



  • The schedule is an external file and reread every time the server restarts so nothing will be forgotten, plus there's no bad side effects for missing an event, so I'm not too worried about that. Adding events without a server restart would be nice, but I expect it to be rare enough that I'm not super worried about it just yet. (edit: I take that back, that's an important thing)



  • This may be just what I need.


  • Discourse touched me in a no-no place

    @dookdook said:

    so I'm not too worried about that.

    Remember to differentiate between “the system cares about it” and “(some of) the users care about it”. The former is important as a programmer, but the latter is why you're doing it in the first place.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.