How to schedule recurring jobs on a Quake AI VM
Coming from another cloud?
▸AWS·Eventbridge Scheduler
This Quake AI feature maps to AWS’s Eventbridge Scheduler.
▸Azure·Automation
This Quake AI feature maps to Azure’s Automation.
▸Google Cloud·Cloud Scheduler
This Quake AI feature maps to Google Cloud’s Cloud Scheduler.
How to schedule recurring jobs on a Quake AI VM
Run a command or script on a fixed schedule inside a Quake AI instance, using either cron or systemd timers.
Prerequisites
- A running Linux instance. See How to create an instance.
- SSH access to the instance. See How to add an SSH key.
- A user with
sudoprivileges on the instance.
Floating IP requirements#
These scheduling patterns require zero floating IPs. Both cron and systemd timers run entirely inside the guest operating system, so a scheduled job needs no inbound network path. A job that calls the Quake AI API or reaches another instance uses the project's private network, which also needs no floating IP. Allocate a floating IP only if you need to reach the instance directly over SSH from outside the project, and one floating IP per instance covers that access.
Choose cron or systemd timers#
Both mechanisms run a command on a schedule. Pick one per job and keep that job's definition in a single place.
Use cron when | Use systemd timers when |
|---|---|
| You want the shortest possible setup for a simple recurring command | You want per-run logging in the system journal |
| The job is self-contained and has no service dependencies | The job depends on another unit, the network, or a mounted volume |
| You are comfortable redirecting output to a file yourself | You want built-in failure handling, run-time limits, and missed-run catch-up |
systemd timers need more configuration upfront and give you logging, dependency ordering, and reliability controls. The rest of this guide shows both, so you can match the mechanism to the job.
Schedule a recurring job#
The example below runs a maintenance script, /usr/local/bin/cleanup-tmp.sh, every day at 02:30 in the instance's local time zone. Replace the script path and schedule with your own.
Each user has a crontab, a table of scheduled commands. Edit the current user's crontab:
crontab -eAdd one line. The five fields are minute, hour, day of month, month, and day of week, followed by the command:
30 2 * * * /usr/local/bin/cleanup-tmp.shSave and exit the editor. List the active entries to confirm the change:
crontab -lThe command runs as the user who owns the crontab. For a job that must run as root, install it in the root crontab with sudo crontab -e, or drop a file in /etc/cron.d/:
# /etc/cron.d/cleanup-tmp
30 2 * * * root /usr/local/bin/cleanup-tmp.shFiles in /etc/cron.d/ include an extra field for the user that runs the command. Keep the schedule readable by adding a comment above each entry that describes what the job does.
Capture output and logs#
A scheduled job produces no terminal output, so route its output somewhere you can read later.
cron mails a job's output to the local user by default, which most cloud instances do not deliver. Redirect both standard output and standard error to a log file in your home directory instead. A user crontab cannot create files under /var/log/ without extra permissions.
Create the log directory, then add the redirect to your crontab:
mkdir -p ~/logs30 2 * * * /usr/local/bin/cleanup-tmp.sh >> ~/logs/cleanup-tmp.log 2>&1Rotate the log so it does not grow without bound. logrotate needs the full path to your home directory:
sudo tee /etc/logrotate.d/cleanup-tmp <<EOF
/home/$(whoami)/logs/cleanup-tmp.log {
weekly
rotate 8
compress
missingok
notifempty
}
EOFTo write logs under /var/log/, install the job in the root crontab with sudo crontab -e or in /etc/cron.d/ as shown earlier.
Handle failures and overlapping runs#
A job that runs longer than its interval can start a second copy before the first finishes, and a job that fails silently can go unnoticed for days. Guard against both.
Wrap the command in flock to take an exclusive lock, so a slow run blocks the next start instead of overlapping it:
30 2 * * * /usr/bin/flock -n /tmp/cleanup-tmp.lock /usr/local/bin/cleanup-tmp.sh >> ~/logs/cleanup-tmp.log 2>&1The -n flag makes flock exit immediately if the lock is held, which skips the run rather than queueing it. For failure visibility, have the script exit non-zero on error and append a timestamped status line to its log, then alert on that line with your monitoring agent.
Worked example: schedule a volume snapshot#
A common scheduled job is a recurring volume snapshot. Install the OpenStack CLI and an application credential on the instance, then schedule a snapshot of a target volume.
Create the script at /usr/local/bin/snapshot-data-volume.sh. Set YOUR_CLOUD to the cloud name in your ~/.config/openstack/clouds.yaml or from your downloaded openrc file. See How to generate application credentials.
#!/usr/bin/env bash
set -euo pipefail
export OS_CLOUD=YOUR_CLOUD
VOLUME_ID="YOUR_VOLUME_ID"
STAMP="$(date -u +%Y%m%d-%H%M%S)"
openstack volume snapshot create \
--volume "$VOLUME_ID" \
--force \
"data-volume-$STAMP"Make the script executable, create the log directory, then schedule it with whichever mechanism you chose above. The cron form runs it nightly at 01:00 UTC under a lock:
chmod +x /usr/local/bin/snapshot-data-volume.sh
mkdir -p ~/logs0 1 * * * /usr/bin/flock -n /tmp/snapshot-data-volume.lock /usr/local/bin/snapshot-data-volume.sh >> ~/logs/snapshot-data-volume.log 2>&1Use an application credential rather than a password so the scheduled job keeps working without interactive login. See How to generate application credentials and How to create an instance snapshot for the snapshot lifecycle. Prune old snapshots on the same schedule with a retention loop so the count stays bounded.
Run a dedicated control VM for ops jobs#
Scheduling each job on the instance it acts against works for instance-local maintenance. For jobs that act on many instances or on Quake AI resources through the API, run them from one small, long-lived control instance instead.
A control VM keeps scheduled operations in a single place you can audit and back up, holds one application credential rather than spreading credentials across the fleet, and isolates ops workloads from production traffic. A shared-vCPU flavor is enough for most control workloads. The control VM needs no floating IP of its own when it reaches the Quake AI API and other instances over the project's private network.
Verify the result#
Confirm the schedule is registered and inspect the most recent run.
List the active crontab entries:
crontab -lAfter the first scheduled run, check the log file you configured:
tail -n 20 ~/logs/cleanup-tmp.logSee also#
- How to create an instance: provision the VM that runs your scheduled jobs
- How to create an instance snapshot: the snapshot operation used in the worked example
- How to generate application credentials: non-interactive credentials for jobs that call the API
- Install the OpenStack CLI: set up the CLI used inside the instance
- How to use the virtual machine console: reach the instance when SSH is unavailable
Usage Guidelines
The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.
For the full policy, see Usage Guidelines.
Last validated: 27.06.2026
Quick answers
- Why does `openstack image save` write a 0-byte file for my boot-from-volume instance?CLI
- Why does `openstack server create` fail with "Only volume-backed servers are allowed for flavors with zero disk"?CLIAPITerraform
- Why does my project still have a 10 GiB Cinder volume after I deleted my instance?CLIAPI