Run Jobs Every 15 Minutes Safely | CronBase
*/15 * * * * Every fifteen minutes, at the start of each quarter-hour interval.
This cron expression schedules a task to execute every fifteen minutes, specifically at the zero, fifteenth, thirtieth, and forty-fifth minute of every hour. It is commonly used for high-frequency operations like processing message queues, checking system health, pulling API updates, or synchronizing lightweight cache databases.
- Minute
- */15
- Hour
- *
- Day of Month
- *
- Month
- *
- Day of Week
- *
Next 5 Runs
- in 6m 20s
- in 21m 20s
- in 36m 20s
- in 51m 20s
- in 1h 6m
* Tools
Code & Implementations
#!/usr/bin/env bash
set -euo pipefail
# Define lock file to prevent overlapping executions
LOCKFILE="/var/lock/quarter_hourly_job.lock"
exec 9>"$LOCKFILE"
# Attempt to acquire an exclusive lock without blocking
if ! flock -n 9; then
echo "[$(date '+$Y-%m-%d %H:%M:%S')] Error: Job is already running. Exiting." >&2
exit 1
fi
echo "[$(date '+$Y-%m-%d %H:%M:%S')] Starting 15-minute maintenance task..."
# Place your production logic here (e.g., database cleanup, log shipping)
# /usr/local/bin/sync-script.sh
echo "[$(date '+$Y-%m-%d %H:%M:%S')] Task completed successfully." › Setup notes
Save this script to /usr/local/bin/my-job.sh, make it executable with 'chmod +x', and register it in your crontab using '*/15 * * * * /usr/local/bin/my-job.sh >> /var/log/my-job.log 2>&1'.
const cron = require('node-cron');
const logger = require('pino')();
let isJobRunning = false;
// Schedule task to run every 15 minutes
cron.schedule('*/15 * * * *', async () => {
if (isJobRunning) {
logger.warn('Previous execution is still running. Skipping this cycle to prevent overlaps.');
return;
}
isJobRunning = true;
logger.info('Starting 15-minute synchronization task...');
const startTime = Date.now();
try {
// Place async business logic here
await performSynchronization();
logger.info({ durationMs: Date.now() - startTime }, 'Task completed successfully.');
} catch (error) {
logger.error({ err: error }, 'Task execution failed.');
} finally {
isJobRunning = false;
}
});
async function performSynchronization() {
return new Promise(resolve => setTimeout(resolve, 5000));
} › Setup notes
Install 'node-cron' and your logging library ('pino' in this example). Run the script using a process manager like PM2 to ensure high availability and automatic restarts.
import logging
import time
from apscheduler.schedulers.blocking import BlockingScheduler
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger("QuarterHourlyJob")
scheduler = BlockingScheduler()
# Coalesce: if multiple executions are missed, run only once.
# max_instances: prevent multiple concurrent instances of this job.
@scheduler.scheduled_job('cron', minute='*/15', coalesce=True, max_instances=1)
def run_task():
logger.info("Executing 15-minute pipeline task...")
start_time = time.time()
try:
# Insert your pipeline, data-sync, or API pulling logic here
time.sleep(10) # Simulating processing
logger.info(f"Job completed successfully in {time.time() - start_time:.2f} seconds.")
except Exception as e:
logger.error(f"Execution encountered an error: {e}", exc_info=True)
if __name__ == "__main__":
try:
logger.info("Starting scheduler daemon...")
scheduler.start()
except (KeyboardInterrupt, SystemExit):
logger.info("Scheduler stopped gracefully.") › Setup notes
Install APScheduler using 'pip install apscheduler'. Run this script as a persistent background daemon, or wrap it in a systemd service file.
package main
import (
"context"
"log"
"sync/atomic"
"time"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
var activeRuns int32
_, err := c.AddFunc("*/15 * * * *", func() {
// Atomic lock to guarantee single concurrency
if !atomic.CompareAndSwapInt32(&activeRuns, 0, 1) {
log.Println("Warning: Overlap detected. Skipping execution.")
return
}
defer atomic.StoreInt32(&activeRuns, 0)
// Set a hard timeout slightly below the schedule interval
ctx, cancel := context.WithTimeout(context.Background(), 14*time.Minute)
defer cancel()
log.Println("Starting quarter-hourly job...")
performWork(ctx)
log.Println("Job run completed.")
})
if err != nil {
log.Fatalf("Error scheduling cron job: %v", err)
}
c.Start()
select {} // Keep application alive
}
func performWork(ctx context.Context) {
select {
case <-time.After(5 * time.Second):
// Work finished
case <-ctx.Done():
log.Println("Error: Task timed out before completion.")
}
} › Setup notes
Initialize a Go module, run 'go get github.com/robfig/cron/v3', compile the binary, and run it as a daemon in your production environment.
package com.example.scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class QuarterHourlyScheduler {
private static final Logger log = LoggerFactory.getLogger(QuarterHourlyScheduler.class);
private boolean isRunning = false;
// Standard cron format: second, minute, hour, day of month, month, day of week
@Scheduled(cron = "0 */15 * * * *")
public synchronized void executeTask() {
if (isRunning) {
log.warn("Previous scheduled run is still active. Skipping execution.");
return;
}
isRunning = true;
log.info("Starting 15-minute synchronization task...");
long startTime = System.currentTimeMillis();
try {
// Implement high-performance batch operations here
Thread.sleep(3000);
log.info("Task completed in {} ms.", (System.currentTimeMillis() - startTime));
} catch (InterruptedException e) {
log.error("Task was interrupted", e);
Thread.currentThread().interrupt();
} catch (Exception e) {
log.error("Error during scheduled execution", e);
} finally {
isRunning = false;
}
}
} › Setup notes
Ensure '@EnableScheduling' is added to your main Spring Boot configuration class. The framework will automatically register and execute this task based on the specified cron expression.
apiVersion: batch/v1
kind: CronJob
metadata:
name: quarter-hourly-cleanup
namespace: production
spec:
schedule: "*/15 * * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 60
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: worker
image: registry.example.com/ops/utility-worker:v1.2.0
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
restartPolicy: OnFailure › Setup notes
Apply this manifest using 'kubectl apply -f cronjob.yaml'. The 'concurrencyPolicy: Forbid' option ensures that if a pod hangs, Kubernetes will not spawn a parallel pod on the next fifteen-minute interval.
Last verified:
Keep this cron job monitored 24/7
UptimeRobot alerts you the moment a scheduled job stops responding. Free plan monitors up to 50 endpoints — no credit card required.
Platform Equivalents
AWS EventBridge
Standard cron expressions often need conversion for AWS EventBridge schedules.
cron(*/15 * * * ? *) Systemd Timer
OnCalendar*-*-* *:00/15:00
[Unit]
Description=Timer for cron expression: */15 * * * *
[Timer]
OnCalendar=*-*-* *:00/15:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
How do I prevent overlapping executions if a task takes longer than 15 minutes?
To prevent overlapping executions, implement a locking mechanism. In single-server environments, use utility wrappers like 'flock' in Bash or atomic flags in application code. In distributed or clustered environments, use a distributed locking library such as Redlock with Redis, or database-backed locks to guarantee mutually exclusive execution.
Does daylight saving time (DST) affect a 15-minute cron schedule?
Because standard cron runs relative to the system's local time, DST transitions can cause duplicate runs or missed runs if the clock steps backward or forward. To maintain strict, uninterrupted fifteen-minute intervals, configure your servers and cron engines to run in UTC (Coordinated Universal Time) which does not observe DST.
How can I add jitter to prevent multiple servers hitting a database at the exact same minute?
To prevent a thundering herd, introduce a randomized sleep delay at the very beginning of your task execution. For example, in Bash, use 'sleep $((RANDOM % 30))' to offset the execution start time dynamically by up to 30 seconds across different servers without changing the core cron schedule.
What is the best way to monitor and alert on failures for this high-frequency job?
Set up a dead man's switch monitoring tool (such as Healthchecks.io or Opsgenie Heartbeats). Configure it to expect an HTTP ping from your job every 15 minutes. If the ping is not received within a 5-minute grace period, trigger an immediate high-priority alert to notify your on-call engineering team.
Can I use standard cron to run a job every 15 minutes but only during business hours?
Yes, you can restrict the hour field in standard cron. For example, using '*/15 9-17 * * 1-5' will run the task every 15 minutes, but only between the hours of 9:00 AM and 5:59 PM, Monday through Friday, aligning the execution perfectly with standard office business hours.
* Explore
Related expressions you might need
Last verified: