How to create on‑calendar job → systemd-run --on-calendar="Mon *-*-* 09:00"
How to Create On-Calendar Jobs with systemd-run --on-calendar Command
Table of Contents
1. [Introduction](#introduction)
2. [Prerequisites](#prerequisites)
3. [Understanding systemd-run and On-Calendar Scheduling](#understanding-systemd-run-and-on-calendar-scheduling)
4. [Basic Syntax and Command Structure](#basic-syntax-and-command-structure)
5. [Calendar Event Format Explained](#calendar-event-format-explained)
6. [Step-by-Step Guide to Creating On-Calendar Jobs](#step-by-step-guide-to-creating-on-calendar-jobs)
7. [Practical Examples and Use Cases](#practical-examples-and-use-cases)
8. [Advanced Configuration Options](#advanced-configuration-options)
9. [Managing and Monitoring Scheduled Jobs](#managing-and-monitoring-scheduled-jobs)
10. [Troubleshooting Common Issues](#troubleshooting-common-issues)
11. [Best Practices and Professional Tips](#best-practices-and-professional-tips)
12. [Comparison with Other Scheduling Methods](#comparison-with-other-scheduling-methods)
13. [Conclusion](#conclusion)
Introduction
The `systemd-run` command with the `--on-calendar` option provides a powerful and flexible way to schedule jobs on Linux systems using systemd. Unlike traditional cron jobs, systemd calendar events offer more precise timing control, better logging integration, and enhanced system resource management. This comprehensive guide will teach you how to create, manage, and troubleshoot on-calendar jobs using the systemd-run command.
By the end of this article, you'll understand how to schedule tasks with various time patterns, from simple daily routines to complex scheduling scenarios. You'll also learn best practices for system administration and automation using systemd's built-in scheduling capabilities.
Prerequisites
Before diving into on-calendar job creation, ensure you have the following:
System Requirements
- Linux distribution with systemd (most modern distributions)
- systemd version 220 or later (for full --on-calendar support)
- Root or sudo privileges for system-wide jobs
- Basic command-line knowledge
Verification Commands
Check your systemd version:
```bash
systemctl --version
```
Verify systemd-run availability:
```bash
which systemd-run
```
Test basic systemd functionality:
```bash
systemctl status
```
Knowledge Prerequisites
- Basic understanding of Linux command line
- Familiarity with systemd concepts
- Understanding of time formats and scheduling concepts
Understanding systemd-run and On-Calendar Scheduling
What is systemd-run?
The `systemd-run` command allows you to run programs in transient scope units, service units, or timer units. When combined with the `--on-calendar` option, it creates temporary timer units that execute commands at specified times.
Key Advantages Over Cron
1. Better Integration: Native systemd integration with improved logging
2. Resource Management: Built-in resource control and isolation
3. Flexible Timing: More precise and flexible time specifications
4. System Dependencies: Can depend on system states and services
5. Centralized Management: Unified management through systemctl
How On-Calendar Scheduling Works
When you use `systemd-run --on-calendar`, systemd creates:
- A transient timer unit that defines when to run
- A transient service unit that defines what to run
- Automatic cleanup after execution
Basic Syntax and Command Structure
Standard Command Format
```bash
systemd-run --on-calendar="CALENDAR_EVENT" [OPTIONS] COMMAND [ARGUMENTS]
```
Essential Components
- `systemd-run`: The base command
- `--on-calendar="..."`: Specifies when to run
- `COMMAND`: The command or script to execute
- `[OPTIONS]`: Additional systemd-run options
- `[ARGUMENTS]`: Arguments for the command
Simple Example Breakdown
```bash
systemd-run --on-calendar="Mon --* 09:00" /usr/bin/backup-script.sh
```
This command:
- Runs every Monday at 9:00 AM
- Executes the backup script
- Creates temporary systemd units
- Provides systemd logging and management
Calendar Event Format Explained
Basic Format Structure
The calendar event format follows this pattern:
```
DayOfWeek Year-Month-Day Hour:Minute:Second
```
Component Breakdown
Day of Week
- `Mon`, `Tue`, `Wed`, `Thu`, `Fri`, `Sat`, `Sun`
- Can be abbreviated: `Mo`, `Tu`, `We`, `Th`, `Fr`, `Sa`, `Su`
- Multiple days: `Mon,Wed,Fri` or `Mon..Fri`
Date Components
- Year: Four digits (2024) or `*` for any year
- Month: 01-12 or `*` for any month
- Day: 01-31 or `*` for any day
Time Components
- Hour: 00-23 in 24-hour format
- Minute: 00-59
- Second: 00-59 (optional)
Wildcard and Range Examples
```bash
Every day at 2:30 PM
"--* 14:30"
Every Monday at 9 AM
"Mon --* 09:00"
Weekdays at 8 AM
"Mon..Fri --* 08:00"
Every 15 minutes
"*:0/15"
First day of every month at midnight
"--01 00:00"
```
Step-by-Step Guide to Creating On-Calendar Jobs
Step 1: Plan Your Scheduling Requirements
Before creating the job, determine:
- When: Exact timing requirements
- What: Command or script to execute
- Where: Working directory requirements
- Who: User context (root or specific user)
- How: Any special environment needs
Step 2: Test Your Command Manually
Always test your command before scheduling:
```bash
Test the actual command first
/path/to/your/script.sh
Verify it works as expected
echo $?
```
Step 3: Create Your First On-Calendar Job
Basic Example: Daily Backup
```bash
systemd-run --on-calendar="daily" \
--unit=daily-backup \
/usr/local/bin/backup-script.sh
```
With Specific Timing
```bash
systemd-run --on-calendar="Mon --* 09:00" \
--unit=monday-maintenance \
/usr/local/bin/system-maintenance.sh
```
Step 4: Verify Job Creation
Check if the timer was created:
```bash
systemctl list-timers --all | grep monday-maintenance
```
View timer details:
```bash
systemctl status monday-maintenance.timer
```
Step 5: Monitor Job Execution
Check service logs:
```bash
journalctl -u monday-maintenance.service
```
View timer logs:
```bash
journalctl -u monday-maintenance.timer
```
Practical Examples and Use Cases
Example 1: System Maintenance Tasks
Weekly System Updates
```bash
systemd-run --on-calendar="Sun --* 02:00" \
--unit=weekly-updates \
--description="Weekly system updates" \
/usr/bin/apt update && /usr/bin/apt upgrade -y
```
Daily Log Rotation
```bash
systemd-run --on-calendar="daily" \
--unit=log-rotation \
--working-directory=/var/log \
/usr/sbin/logrotate /etc/logrotate.conf
```
Example 2: Backup Operations
Database Backup Every 6 Hours
```bash
systemd-run --on-calendar="--* 00,06,12,18:00" \
--unit=database-backup \
--setenv=BACKUP_DIR=/backup/db \
/usr/local/bin/db-backup.sh
```
Weekly Full Backup
```bash
systemd-run --on-calendar="Sat --* 23:00" \
--unit=full-backup \
--nice=19 \
--ioprio=3 \
/usr/local/bin/full-system-backup.sh
```
Example 3: Monitoring and Alerts
Hourly Disk Space Check
```bash
systemd-run --on-calendar="hourly" \
--unit=disk-space-check \
/usr/local/bin/check-disk-space.sh
```
Daily Security Scan
```bash
systemd-run --on-calendar="--* 01:30" \
--unit=security-scan \
--timeout=3600 \
/usr/bin/rkhunter --check --skip-keypress
```
Example 4: Development and Deployment
Nightly Build Process
```bash
systemd-run --on-calendar="--* 02:00" \
--unit=nightly-build \
--uid=builduser \
--gid=buildgroup \
--working-directory=/home/builduser/project \
/usr/local/bin/nightly-build.sh
```
Certificate Renewal Check
```bash
systemd-run --on-calendar="--01 03:00" \
--unit=cert-renewal \
--remain-after-exit \
/usr/bin/certbot renew --quiet
```
Advanced Configuration Options
Resource Management Options
CPU and Memory Limits
```bash
systemd-run --on-calendar="daily" \
--unit=resource-limited-job \
--property=CPUQuota=50% \
--property=MemoryLimit=512M \
/usr/local/bin/intensive-task.sh
```
I/O Priority Settings
```bash
systemd-run --on-calendar="--* 03:00" \
--unit=low-priority-backup \
--nice=19 \
--ioprio=3 \
/usr/local/bin/backup.sh
```
Environment and Security Options
Custom Environment Variables
```bash
systemd-run --on-calendar="Mon --* 08:00" \
--unit=env-job \
--setenv=API_KEY=secret123 \
--setenv=LOG_LEVEL=INFO \
/usr/local/bin/api-sync.sh
```
Running as Different User
```bash
systemd-run --on-calendar="daily" \
--unit=user-job \
--uid=webapp \
--gid=webapp \
--working-directory=/var/www/app \
/usr/local/bin/app-maintenance.sh
```
Dependency Management
Service Dependencies
```bash
systemd-run --on-calendar="--* 04:00" \
--unit=dependent-job \
--property=After=network-online.target \
--property=Wants=network-online.target \
/usr/local/bin/network-dependent-task.sh
```
Complex Calendar Expressions
Multiple Time Specifications
```bash
systemd-run --on-calendar="Mon,Wed,Fri --* 09:00,17:00" \
--unit=multi-time-job \
/usr/local/bin/periodic-task.sh
```
Interval-Based Scheduling
```bash
systemd-run --on-calendar="*:0/30" \
--unit=every-30-minutes \
/usr/local/bin/frequent-check.sh
```
Managing and Monitoring Scheduled Jobs
Listing Active Timers
View all active timers:
```bash
systemctl list-timers
```
Show all timers (including inactive):
```bash
systemctl list-timers --all
```
Filter specific timers:
```bash
systemctl list-timers --all | grep backup
```
Controlling Timer Units
Start/Stop Timers
```bash
Stop a timer
systemctl stop monday-maintenance.timer
Start a timer
systemctl start monday-maintenance.timer
Restart a timer
systemctl restart monday-maintenance.timer
```
Enable/Disable Timers
```bash
Enable timer to start at boot
systemctl enable monday-maintenance.timer
Disable timer
systemctl disable monday-maintenance.timer
```
Monitoring Job Execution
Real-time Log Monitoring
```bash
Follow logs for a specific service
journalctl -u monday-maintenance.service -f
Show recent logs
journalctl -u monday-maintenance.service --since "1 hour ago"
```
Checking Job Status
```bash
View service status
systemctl status monday-maintenance.service
Check last execution time
systemctl show monday-maintenance.timer -p LastTriggerUSec
```
Modifying Existing Jobs
Changing Schedule
To modify an existing job, you typically need to:
1. Stop the current timer
2. Create a new job with updated schedule
3. Remove the old timer unit
```bash
Stop existing timer
systemctl stop old-job.timer
Create new job
systemd-run --on-calendar="new-schedule" \
--unit=updated-job \
/path/to/command
Clean up old unit (if needed)
systemctl reset-failed old-job.service
```
Troubleshooting Common Issues
Issue 1: Timer Not Executing
Symptoms
- Timer shows as active but job never runs
- No logs in journal for the service
Diagnosis Steps
```bash
Check timer status
systemctl status job-name.timer
Verify calendar expression
systemd-analyze calendar "your-calendar-expression"
Check system time
timedatectl status
```
Solutions
```bash
Restart systemd-timesyncd if time is wrong
systemctl restart systemd-timesyncd
Reload systemd if units are corrupted
systemctl daemon-reload
Check for syntax errors in calendar expression
systemd-analyze calendar "Mon --* 09:00"
```
Issue 2: Command Not Found or Permission Errors
Symptoms
- Service fails with "command not found"
- Permission denied errors in logs
Diagnosis
```bash
Check service logs
journalctl -u job-name.service
Verify command path
which command-name
Check file permissions
ls -la /path/to/script
```
Solutions
```bash
Use full path to command
systemd-run --on-calendar="daily" /usr/bin/full-path-to-command
Fix script permissions
chmod +x /path/to/script
Run as appropriate user
systemd-run --on-calendar="daily" --uid=username /path/to/script
```
Issue 3: Environment Variables Not Available
Symptoms
- Script fails because environment variables are missing
- Commands work manually but fail when scheduled
Solutions
```bash
Set environment variables explicitly
systemd-run --on-calendar="daily" \
--setenv=PATH=/usr/local/bin:/usr/bin:/bin \
--setenv=HOME=/root \
/path/to/script
Source environment in script
systemd-run --on-calendar="daily" \
/bin/bash -c "source /etc/environment && /path/to/script"
```
Issue 4: Jobs Running Multiple Times
Symptoms
- Same job appears to run multiple times
- Duplicate entries in logs
Diagnosis
```bash
Check for duplicate timers
systemctl list-timers | grep job-name
Look for multiple units with same name
systemctl list-units --all | grep job-name
```
Solutions
```bash
Stop all related units
systemctl stop job-name.*
Reset failed states
systemctl reset-failed
Create single new job
systemd-run --on-calendar="schedule" --unit=unique-name /command
```
Best Practices and Professional Tips
Security Best Practices
Principle of Least Privilege
```bash
Run jobs as non-root when possible
systemd-run --on-calendar="daily" \
--uid=serviceuser \
--gid=servicegroup \
/usr/local/bin/user-script.sh
```
Secure Script Permissions
```bash
Set proper permissions on scripts
chmod 750 /usr/local/bin/scheduled-script.sh
chown root:admin /usr/local/bin/scheduled-script.sh
```
Resource Management Best Practices
Resource Limits for Heavy Jobs
```bash
systemd-run --on-calendar="--* 02:00" \
--unit=heavy-job \
--property=CPUQuota=25% \
--property=MemoryLimit=1G \
--property=IOWeight=100 \
--nice=19 \
/usr/local/bin/resource-intensive-task.sh
```
Timeout Configuration
```bash
systemd-run --on-calendar="daily" \
--unit=timed-job \
--property=TimeoutSec=1800 \
/usr/local/bin/long-running-task.sh
```
Logging and Monitoring Best Practices
Structured Logging
```bash
Configure job with proper logging
systemd-run --on-calendar="daily" \
--unit=logged-job \
--property=StandardOutput=journal \
--property=StandardError=journal \
--property=SyslogIdentifier=my-scheduled-job \
/usr/local/bin/task.sh
```
Log Retention
```bash
Configure journal retention for job logs
mkdir -p /etc/systemd/journald.conf.d/
echo -e "[Journal]\nMaxRetentionSec=30day" > /etc/systemd/journald.conf.d/retention.conf
```
Development and Testing Best Practices
Testing Calendar Expressions
```bash
Always test calendar expressions
systemd-analyze calendar "Mon,Wed,Fri --* 09:00,17:00"
Check next execution times
systemd-analyze calendar "daily" --iterations=5
```
Dry Run Testing
```bash
Test command execution without scheduling
systemd-run --no-block --unit=test-job /path/to/script
Check immediate execution
systemctl status test-job.service
```
Documentation and Maintenance
Descriptive Unit Names
```bash
Use descriptive unit names
systemd-run --on-calendar="daily" \
--unit=daily-database-backup-production \
--description="Daily backup of production database" \
/usr/local/bin/db-backup.sh
```
Version Control for Scripts
- Keep scheduled scripts in version control
- Document schedule changes in commit messages
- Use configuration management tools for deployment
Performance Optimization
Staggered Execution
```bash
Avoid running all jobs at the same time
Instead of: --* 02:00
Use staggered times:
systemd-run --on-calendar="--* 02:15" --unit=job1 /cmd1
systemd-run --on-calendar="--* 02:30" --unit=job2 /cmd2
systemd-run --on-calendar="--* 02:45" --unit=job3 /cmd3
```
Resource-aware Scheduling
```bash
Schedule I/O intensive jobs during off-peak hours
systemd-run --on-calendar="--* 03:00" \
--unit=backup-job \
--ioprio=3 \
--nice=19 \
/usr/local/bin/backup.sh
```
Comparison with Other Scheduling Methods
systemd-run vs. Cron
| Feature | systemd-run | Cron |
|---------|-------------|------|
| Integration | Native systemd | Separate daemon |
| Logging | journald integration | Separate log files |
| Resource Control | Built-in limits | Manual nice/ionice |
| Dependencies | Service dependencies | None |
| Flexibility | High precision timing | Limited precision |
| Learning Curve | Steeper | Simpler |
systemd-run vs. Persistent Timer Units
| Aspect | systemd-run | Persistent Timers |
|--------|-------------|-------------------|
| Persistence | Transient | Persistent |
| Boot Survival | No | Yes |
| Configuration | Command-line | Unit files |
| Complexity | Simple | More complex |
| Use Case | Temporary/testing | Production systems |
When to Use systemd-run
Ideal for:
- Quick testing of scheduled jobs
- Temporary scheduling needs
- One-off scheduled tasks
- Development and prototyping
Not ideal for:
- Critical production jobs requiring persistence
- Jobs that must survive reboots
- Complex job dependencies
- Jobs requiring detailed configuration
Conclusion
The `systemd-run --on-calendar` command provides a powerful and flexible way to schedule jobs on modern Linux systems. Throughout this guide, we've explored everything from basic syntax to advanced configuration options, practical examples, and troubleshooting techniques.
Key Takeaways
1. Flexibility: systemd calendar events offer more precise timing control than traditional cron
2. Integration: Native systemd integration provides better logging and resource management
3. Simplicity: Quick command-line job creation without writing unit files
4. Monitoring: Built-in monitoring and logging through systemctl and journalctl
5. Resource Control: Advanced options for CPU, memory, and I/O management
Next Steps
To further develop your systemd scheduling skills:
1. Practice: Create test jobs with various calendar expressions
2. Monitor: Set up monitoring for your scheduled jobs
3. Document: Maintain documentation of your scheduled tasks
4. Explore: Learn about persistent systemd timer units for production use
5. Automate: Consider using configuration management tools to deploy scheduled jobs
Final Recommendations
- Start with simple schedules and gradually increase complexity
- Always test commands manually before scheduling
- Use descriptive unit names and descriptions
- Implement proper logging and monitoring
- Follow security best practices with appropriate user permissions
- Consider resource limits for intensive tasks
The `systemd-run --on-calendar` command bridges the gap between quick ad-hoc scheduling and full systemd timer unit implementation, making it an invaluable tool for system administrators and developers working with modern Linux systems. By mastering these techniques, you'll be able to create robust, well-monitored scheduled jobs that integrate seamlessly with your system's service management infrastructure.
Remember that while systemd-run is excellent for temporary and testing scenarios, production environments may benefit from persistent systemd timer units that survive system reboots and provide more comprehensive configuration options. Use the knowledge gained here as a foundation for exploring the full capabilities of systemd's timing and scheduling features.