#636·schedule

Daylight saving to winter time caused scheduler to stop

Author: kimdreCreated Oct 27, 2024Updated Oct 31, 2025

Tonight my scheduler app stopped running right after the time was set back by one hour. Did anyone experience something similiar? Unfortunately there were no errors/exceptions in the logs, this is the only information I can provide:

python
[2024-10-27 02:59:12.406] [client.py.start_scheduler:83] INFO: Running pending jobs: ['check_100th_checkins']
[2024-10-27 02:01:40.857] [main.py.<module>:28] INFO: Stopping App...
[2024-10-27 02:01:40.861] [main.py.<module>:33] INFO: App stopped.

My main:

python
if __name__ == '__main__':
    log.info("Starting App...")

    loop = asyncio.new_event_loop()

    mq_connection = loop.run_until_complete(get_connection(loop))
    message_publisher = MessagePublisher(mq_connection)

    try:
        loop.run_until_complete(message_publisher.connect())
        loop.run_until_complete(start_scheduler(loop=loop, message_publisher=message_publisher))

    except (KeyboardInterrupt, SystemExit):
        pass

    except Exception as e:
        log.error(e, exc_info=True)

    finally:
        log.info("Stopping App...")
        loop.run_until_complete(message_publisher.disconnect())
        loop.run_until_complete(mq_connection.close())
        loop.stop()
        loop.close()
        log.info("App stopped.")

My scheduler:

python
def run_async(func, loop: asyncio.AbstractEventLoop, *args):
    """
    Wrapper to run async functions in the scheduler

    :param func: The async function to run
    :param loop: The event loop
    :param args: The arguments to pass to the function
    """

    logger.debug(f"Running async function: {func}")
    loop.call_soon_threadsafe(loop.create_task, func(*args))


async def start_scheduler(loop: asyncio.AbstractEventLoop, message_publisher: MessagePublisher):
    """
    Start the scheduler

    :param message_publisher: The message publisher
    :param loop: The event loop
    """

    logger.info("Starting scheduler...")

    # Health check job

    schedule.every(5).seconds.do(run_async, write_health, loop)
    schedule.run_all()

    # Schedule normal jobs

    schedule.every(15).minutes.do(run_async, check_100th_checkins, loop, message_publisher)

    schedule.every().day.at("10:00").do(run_async, check_birthdays, loop, message_publisher)
    schedule.every().day.at("10:15").do(run_async, check_inactive_midterm_members_premium, loop, message_publisher)
    schedule.every().day.at("10:30").do(run_async, check_inactive_longterm_members_premium, loop, message_publisher)
    schedule.every().day.at("10:45").do(run_async, check_active_members_weekend_only_premium, loop, message_publisher)
    schedule.every().day.at("12:45").do(run_async, check_inactive_new_members_premium, loop, message_publisher)
    schedule.every().day.at("13:00").do(run_async, check_inactive_members, loop, message_publisher)

    logger.info("Scheduler started.")

    # Create multiline string with scheduled job names, interval and next run time
    jobs = "\n• ".join(
        [
            f"{job.job_func.args[0].__name__} - runs at {job.at_time or f'every {job.interval} {job.unit}'} - next run: {job.next_run}"
            for job in schedule.jobs
        ]
    )
    logger.info(f"Scheduled jobs:\n• {jobs}")

    while True:
        try:
            pending_jobs = get_pending_jobs(schedule.jobs)
            if pending_jobs:
                jobs = [job.job_func.args[0].__name__ for job in pending_jobs]
                logger.info(f"Running pending jobs: {jobs}")
            schedule.run_pending()
            await asyncio.sleep(1)
        except asyncio.CancelledError:
            break

    logger.info("Scheduler stopped.")