Search code examples
pythontornado

How to start Tornado periodic callback at a specific time?


Currently in my Tornado application, I am calling a callback periodically using PeriodicCallback every hour. Like this:

import tornado.ioloop
from tornado.ioloop import PeriodicCallback

if __name__ == "__main__":
    tornado.options.parse_command_line()
    app = tornado.web.Application(
      handlers=urls,
      template_path=os.path.join(os.path.dirname(__file__), "templates"),
      static_path=os.path.join(os.path.dirname(__file__), "static"),
      debug=True
      )
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)

    # Here i have option to specify interval, but how to specify when to start?
    daily_alerts = PeriodicCallback(lambda: send_email.daily_alert(), 3600000)
    daily_alerts.start()
    tornado.ioloop.IOLoop.instance().start()

Here, I have the option to set the interval time (3600000), but how do I specify when this periodical callback should start?


Solution

  • If you want to control exactly when the callback is scheduled, it's better to use IOLoop.add_timeout directly instead of PeriodicCallback.

    def schedule_next_email():
        tomorrow = datetime.date.today() + datetime.timedelta(days=1)
        midnight = datetime.combine(tomorrow, datetime.time.min)
        def wrapper():
            send_email.daily_alert()
            schedule_next_email()
        IOLoop.current().add_timeout(midnight, wrapper)
    
    schedule_next_email()  # call at startup to schedule first call
    

    Recomputing the interval every time helps you send at the same time every day even when daylight savings time changes and days can have either 23 or 25 hours.