Run Daily Maintenance at 1:30 AM | CronBase
30 1 * * * At half past one in the morning every single day
This cron expression schedules a task to execute automatically every day at exactly 1:30 AM. It is widely used in production environments for off-peak operations such as database backups, log rotation, clearing temporary caches, and synchronizing daily analytical data when user activity and system load are at their lowest.
- Minute
- 30
- Hour
- 1
- Day of Month
- *
- Month
- *
- Day of Week
- *
Next 5 Runs
- in 4h 53m
- in 1d 4h
- in 2d 4h
- in 3d 4h
- in 4d 4h
* Tools
Code & Implementations
#!/bin/bash
# System crontab entry for daily maintenance at 1:30 AM
# Uses flock to prevent overlapping runs and redirects output to a logfile with timestamps
# Installation: Add this to your crontab using 'crontab -e':
# 30 1 * * * /usr/local/bin/daily-cleanup.sh >> /var/log/daily-cleanup.log 2>&1
LOCKFILE="/var/run/daily-cleanup.lock"
exec 9>"$LOCKFILE"
if ! flock -n 9; then
echo "[$(date -u)] Script is already running. Exiting to prevent overlap." >&2
exit 1
fi
echo "[$(date -u)] Starting daily maintenance task..."
# Perform maintenance tasks (e.g., clearing tmp, rotating files)
# Add your production logic here...
exit 0 › Setup notes
Add the script to your server, make it executable with chmod +x, and register the job using 'crontab -e' with the schedule '30 1 * * *'.
const cron = require('node-cron');
const { exec } = require('child_process');
// Schedule task to run daily at 1:30 AM in UTC
cron.schedule('30 1 * * *', () => {
console.log(`[${new Date().toISOString()}] Initiating daily database backup...`);
try {
exec('/usr/local/bin/backup-db.sh', (error, stdout, stderr) => {
if (error) {
console.error(`Backup execution error: ${error.message}`);
return;
}
if (stderr) {
console.warn(`Backup process warning: ${stderr}`);
}
console.log(`Backup completed: ${stdout}`);
});
} catch (err) {
console.error('Unexpected execution error during daily cron:', err);
}
}, {
scheduled: true,
timezone: "UTC"
}); › Setup notes
Install the node-cron library via npm, then execute this script as a long-running daemon process using PM2 or systemd.
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
import logging
import sys
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def daily_sync_job():
logging.info("Starting daily data synchronization pipeline...")
try:
# Place ETL or synchronization logic here
pass
except Exception as e:
logging.error(f"Sync job failed: {str(e)}")
# In production, hook into an alerting service like Sentry or PagerDuty
if __name__ == "__main__":
scheduler = BlockingScheduler()
# 30 1 * * * translates to hour=1, minute=30
trigger = CronTrigger(hour=1, minute=30, timezone='UTC')
scheduler.add_job(daily_sync_job, trigger=trigger, id='daily_sync_id')
try:
logging.info("Scheduler started. Waiting for 01:30 UTC...")
scheduler.start()
except (KeyboardInterrupt, SystemExit):
logging.info("Scheduler stopped cleanly.")
sys.exit(0) › Setup notes
Install apscheduler via pip, write the script to main.py, and run it as a persistent service inside your environment.
package main
import (
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/robfig/cron/v3"
)
func main() {
// Use UTC location to avoid Daylight Saving Time issues
utc, err := time.LoadLocation("UTC")
if err != nil {
log.Fatalf("Failed to load UTC location: %v", err)
}
c := cron.New(cron.WithLocation(utc))
// 30 1 * * * runs at 1:30 AM daily
_, err = c.AddFunc("30 1 * * *", func() {
log.Println("Daily data pipeline execution started...")
executeDataPipeline()
})
if err != nil {
log.Fatalf("Error scheduling daily job: %v", err)
}
c.Start()
log.Println("Cron scheduler started in UTC mode.")
// Handle graceful shutdown
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
log.Println("Stopping scheduler...")
c.Stop()
}
func executeDataPipeline() {
// Processing logic goes here
log.Println("Daily data pipeline completed successfully.")
} › Setup notes
Initialize your Go module, fetch robfig/cron/v3, compile the executable, and run it as a background service.
package com.example.scheduler;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
public class DailyMaintenanceScheduler {
private static final Logger logger = LoggerFactory.getLogger(DailyMaintenanceScheduler.class);
// Spring cron uses 6 fields: second, minute, hour, day, month, day-of-week.
// "0 30 1 * * *" executes at 1:30:00 AM every day.
// Zone is explicitly set to UTC to guarantee predictable execution times.
@Scheduled(cron = "0 30 1 * * *", zone = "UTC")
public void runDailyCleanup() {
logger.info("Executing scheduled daily cleanup task...");
try {
performCleanupTasks();
logger.info("Daily cleanup completed successfully.");
} catch (Exception e) {
logger.error("Error occurred during scheduled daily cleanup: ", e);
// Implement alerting hook here
}
}
private void performCleanupTasks() {
// Application-specific cleanup logic
}
} › Setup notes
Ensure @EnableScheduling is active in your Spring Boot application config, and add this component to your scanned classpath.
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-db-backup
namespace: production
spec:
schedule: "30 1 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: backup-worker
image: postgres:15-alpine
command:
- /bin/sh
- -c
- "pg_dump -h db-host -U postgres dbname > /mnt/backups/db-$(date +%F).sql"
volumeMounts:
- name: backup-storage
mountPath: /mnt/backups
restartPolicy: OnFailure
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: backup-pvc › Setup notes
Save this spec to a YAML file and apply it to your cluster using 'kubectl apply -f filename.yaml'. Ensure your cluster timezone is configured correctly.
Last verified:
Monitor this schedule in production
Get alerted the moment this cron job fails, is late, or doesn't run. BetterStack tracks execution, duration, and output — no infrastructure required.
Platform Equivalents
AWS EventBridge
Standard cron expressions often need conversion for AWS EventBridge schedules.
cron(30 1 * * ? *) Systemd Timer
OnCalendar*-*-* 01:30:00
[Unit]
Description=Timer for cron expression: 30 1 * * *
[Timer]
OnCalendar=*-*-* 01:30:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
How does Daylight Saving Time affect the 1:30 AM execution?
During DST transitions, the 1:30 AM slot can be tricky. When clocks spring forward, 1:30 AM is skipped in some local timezones, meaning your job might not run. When clocks fall back, it might execute twice. To avoid this, always run your system cron daemons in UTC.
Why should I schedule backups at 1:30 AM instead of midnight?
Midnight is the default target for many automated tasks, leading to severe resource contention, high CPU spikes, and network bottlenecks. Shifting your resource-heavy tasks to 1:30 AM isolates your workload from standard midnight rollups and ensures smoother execution.
How do I prevent a slow-running 1:30 AM job from overlapping?
Use a locking utility like `flock` in Linux or implement a distributed lock manager (like Redis-based Redlock) in your application. This ensures that if the previous day's execution is still running for over 24 hours, the new instance will safely abort.
Can I run this job only on weekdays using standard cron?
Yes, you can easily restrict this schedule to weekdays by changing the last field. Modifying the expression to `30 1 * * 1-5` will execute your task at 1:30 AM from Monday through Friday, skipping the weekend entirely.
How should I monitor if the 1:30 AM job failed to run?
Implement dead man's snitches or health checks. Have your job ping an external monitoring service (like Cronitor or Sentry) upon successful completion. If the service doesn't receive the ping by 1:45 AM, it triggers an alert for your on-call engineering team.
* Explore
Related expressions you might need
Last verified: