Python
Timer
Scheduling
Automation
Programming

Execute specified function every X seconds

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Running a function at regular intervals is a common requirement for monitoring, polling, cleanup tasks, and heartbeat mechanisms. In Python, the main approaches are time.sleep() in a loop (simplest), threading.Timer (non-blocking), sched module (event scheduler), and third-party libraries like schedule and APScheduler (feature-rich). In JavaScript, use setInterval(). Each approach has different tradeoffs in precision, blocking behavior, and error handling. This article covers the idiomatic solution for each language and use case.

Python: time.sleep() Loop

The simplest approach — runs the function in the current thread:

python
1import time
2
3def check_status():
4    print(f"[{time.strftime('%H:%M:%S')}] Checking status...")
5
6# Run every 5 seconds (blocks the thread)
7while True:
8    check_status()
9    time.sleep(5)

This blocks the thread, so nothing else can run. The actual interval is execution_time + 5 seconds, not exactly 5 seconds.

Drift-Corrected Loop

python
1import time
2
3def run_every(interval, func):
4    next_run = time.monotonic()
5    while True:
6        func()
7        next_run += interval
8        sleep_time = next_run - time.monotonic()
9        if sleep_time > 0:
10            time.sleep(sleep_time)
11
12run_every(5, check_status)
13# Compensates for execution time to maintain consistent intervals

Python: threading.Timer (Non-Blocking)

python
1import threading
2import time
3
4def repeated_task():
5    print(f"[{time.strftime('%H:%M:%S')}] Running task")
6
7class RepeatingTimer:
8    def __init__(self, interval, function):
9        self.interval = interval
10        self.function = function
11        self._timer = None
12        self._running = False
13
14    def _run(self):
15        self._running = False
16        self.start()  # Reschedule
17        self.function()
18
19    def start(self):
20        if not self._running:
21            self._timer = threading.Timer(self.interval, self._run)
22            self._timer.daemon = True
23            self._timer.start()
24            self._running = True
25
26    def stop(self):
27        if self._timer:
28            self._timer.cancel()
29        self._running = False
30
31# Usage
32timer = RepeatingTimer(5, repeated_task)
33timer.start()
34
35# Do other work while timer runs in background
36time.sleep(20)
37timer.stop()

Python: schedule Library

The schedule library provides a human-readable API:

python
1import schedule
2import time
3
4def job():
5    print("Running scheduled job...")
6
7def send_report():
8    print("Sending daily report...")
9
10# Schedule jobs
11schedule.every(10).seconds.do(job)
12schedule.every(5).minutes.do(job)
13schedule.every().hour.do(job)
14schedule.every().day.at("10:30").do(send_report)
15schedule.every().monday.do(job)
16
17# Run the scheduler
18while True:
19    schedule.run_pending()
20    time.sleep(1)

Install with pip install schedule.

With Arguments

python
1import schedule
2
3def greet(name):
4    print(f"Hello, {name}!")
5
6schedule.every(3).seconds.do(greet, "Alice")
7
8# Or with a lambda
9schedule.every(3).seconds.do(lambda: greet("Bob"))

Python: asyncio (Async)

python
1import asyncio
2
3async def periodic_task(interval, func):
4    while True:
5        func()
6        await asyncio.sleep(interval)
7
8async def check_api():
9    print("Checking API...")
10
11async def main():
12    # Run multiple periodic tasks concurrently
13    task1 = asyncio.create_task(periodic_task(5, lambda: print("Task 1")))
14    task2 = asyncio.create_task(periodic_task(10, lambda: print("Task 2")))
15
16    await asyncio.gather(task1, task2)
17
18asyncio.run(main())

JavaScript: setInterval()

javascript
1// Run every 3 seconds
2const intervalId = setInterval(() => {
3  console.log(`[${new Date().toLocaleTimeString()}] Running task`);
4}, 3000);
5
6// Stop after 15 seconds
7setTimeout(() => {
8  clearInterval(intervalId);
9  console.log("Stopped");
10}, 15000);

With Async/Await

javascript
1async function fetchData() {
2  const response = await fetch("https://api.example.com/status");
3  const data = await response.json();
4  console.log("Status:", data.status);
5}
6
7// setInterval does not await async functions
8// Use recursive setTimeout instead
9async function poll(fn, interval) {
10  await fn();
11  setTimeout(() => poll(fn, interval), interval);
12}
13
14poll(fetchData, 5000);

Python: APScheduler (Production-Ready)

python
1from apscheduler.schedulers.background import BackgroundScheduler
2from apscheduler.triggers.interval import IntervalTrigger
3import time
4
5def my_job():
6    print(f"[{time.strftime('%H:%M:%S')}] Job executed")
7
8scheduler = BackgroundScheduler()
9scheduler.add_job(my_job, IntervalTrigger(seconds=10))
10scheduler.add_job(my_job, 'cron', hour=2, minute=30)  # At 2:30 AM
11scheduler.start()
12
13try:
14    while True:
15        time.sleep(1)
16except KeyboardInterrupt:
17    scheduler.shutdown()

Install with pip install apscheduler.

Comparison

ApproachLanguageBlocking?Error HandlingPrecision
time.sleep loopPythonYesManual try/exceptDrifts with execution time
threading.TimerPythonNoManualModerate
schedulePythonYes (event loop)ManualSecond-level
asyncio.sleepPythonNo (async)try/except in coroutineModerate
APSchedulerPythonNo (background)Built-in retry/loggingHigh
setIntervalJavaScriptNoUncaught → consoleMillisecond

Common Pitfalls

  • Not handling exceptions in the scheduled function: If the function throws an exception in a time.sleep loop, the entire loop stops. Wrap the function call in try/except to ensure the loop continues: try: func() except Exception as e: log(e).
  • Accumulating drift with time.sleep(interval): The actual interval becomes execution_time + sleep_time. For precise intervals, compute the next run time and sleep only the remaining duration using time.monotonic().
  • Using setInterval for async operations in JavaScript: setInterval does not wait for async functions to complete. If the function takes longer than the interval, multiple executions overlap. Use recursive setTimeout with await instead.
  • Forgetting to make timer threads daemon threads: Non-daemon timer threads prevent the Python process from exiting. Set timer.daemon = True or call timer.cancel() during shutdown to allow clean process termination.
  • Using schedule library without calling run_pending() in a loop: schedule.every(10).seconds.do(job) only registers the job — it does not execute it. You must call schedule.run_pending() repeatedly in a loop for jobs to actually run.

Summary

  • Use time.sleep() in a loop for simple, blocking periodic tasks
  • Use threading.Timer or the schedule library for non-blocking background execution
  • Use asyncio.sleep() for async applications with multiple concurrent periodic tasks
  • Use APScheduler for production systems that need cron scheduling, persistence, and error handling
  • In JavaScript, prefer recursive setTimeout over setInterval for async operations to prevent overlapping executions

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.