Code
Programming
Automation
Timers
Scripting

Run certain code every n seconds

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Running code every n seconds looks trivial until you need reliability under load, graceful shutdown, and error handling. A naive timer can drift, overlap executions, or silently stop after an exception. The right design depends on whether you need best-effort periodic callbacks, strict non-overlapping jobs, or durable scheduled tasks.

Basic Timer Approaches by Runtime

Most runtimes provide built-in periodic scheduling primitives.

JavaScript simple interval:

javascript
1let count = 0;
2const id = setInterval(() => {
3  count += 1;
4  console.log("tick", count, new Date().toISOString());
5  if (count >= 5) clearInterval(id);
6}, 2000);

Python loop:

python
1import time
2
3for i in range(5):
4    print("tick", i)
5    time.sleep(2)

These are fine for simple scripts, but production jobs need additional control.

Prevent Overlapping Execution

If a job can take longer than interval duration, fixed intervals can create overlap. A safer pattern schedules next run only after current run completes.

javascript
1async function doWork() {
2  await new Promise((r) => setTimeout(r, 1200));
3  console.log("work done", Date.now());
4}
5
6async function loop() {
7  try {
8    await doWork();
9  } finally {
10    setTimeout(loop, 2000);
11  }
12}
13
14loop();

This gives non-overlapping behavior and naturally back-pressures slow tasks.

Cancellation and Shutdown Control

Production services need clean stop behavior. In Python, threading.Event is a practical cancellation mechanism.

python
1import threading
2
3stop_event = threading.Event()
4
5
6def worker(interval=2):
7    while not stop_event.is_set():
8        print("polling")
9        stop_event.wait(interval)
10
11thread = threading.Thread(target=worker, daemon=True)
12thread.start()
13
14# later in shutdown path
15stop_event.set()
16thread.join()

Cancellation-aware loops are safer than hard sleeps during shutdown.

C# Async Periodic Pattern

In modern .NET, PeriodicTimer offers clear async semantics.

csharp
1using System;
2using System.Threading;
3using System.Threading.Tasks;
4
5public static async Task RunAsync(CancellationToken token)
6{
7    using var timer = new PeriodicTimer(TimeSpan.FromSeconds(2));
8    while (await timer.WaitForNextTickAsync(token))
9    {
10        Console.WriteLine(DateTime.UtcNow);
11    }
12}

This integrates cleanly with hosted-service cancellation tokens.

Drift, Jitter, and Clock Reality

No in-process timer is perfectly precise. Delay sources include scheduler contention, garbage collection, blocking I O, and machine sleep. If exact cadence matters, compute next target timestamp and adjust wait duration rather than chaining fixed sleeps.

For critical scheduling guarantees, external schedulers or queue systems are often better than in-process loops.

Error Handling and Resilience

Always isolate job exceptions so one failure does not stop the scheduler.

python
1def run_job_safely():
2    try:
3        do_work()
4    except Exception as exc:
5        print(f"job failed: {exc}")

Add retry with backoff for transient remote failures. Without this, periodic jobs can hammer unstable dependencies.

Cron and External Schedulers

If the task is independent and does not need in-process state, cron or a scheduler service may be simpler and more reliable.

bash
*/5 * * * * /usr/bin/python3 /opt/jobs/sync.py >> /var/log/sync.log 2>&1

External scheduling decouples task cadence from application process uptime.

Monitoring and Operational Signals

Track these metrics for periodic jobs:

  • execution duration
  • success and failure counts
  • delay from planned schedule time
  • overlap or skipped runs

Monitoring reveals scheduler stress before users notice missing or delayed background work.

Idempotency for Periodic Jobs

Periodic tasks should be designed as idempotent whenever possible. If a retry or overlapping run happens unexpectedly, idempotent behavior prevents duplicate side effects and data corruption.

Common Pitfalls

  • Assuming timer callbacks run at exact intervals under load.
  • Allowing overlapping runs when job duration is variable.
  • Ignoring cancellation and forcing process shutdown.
  • Letting unhandled exceptions terminate periodic loops.
  • Using in-process timers for jobs that require durable scheduling guarantees.

Summary

  • Periodic execution needs more than a simple interval call in production.
  • Use non-overlapping patterns when task duration is unpredictable.
  • Add cancellation, error handling, and retry logic.
  • Choose external schedulers for durable or process-independent jobs.
  • Monitor drift and execution outcomes to keep periodic workflows reliable.

Course illustration
Course illustration

All Rights Reserved.