Batch Job Submission
Last updated on 2026-08-27 | Edit this page
Estimated time: 35 minutes
Overview
Questions
- How do I submit a batch job?
- How do I check job status and progress?
- Where are my job results, and how do I follow them in real time?
- How do I get email notifications without spamming myself?
Objectives
- Submit jobs with
sbatchand verify submission - Read SLURM status codes and find the cause of pending jobs
- Locate and view output files during and after a run
- Configure email notifications appropriately for the job size
- Recognize and avoid the most common submission mistakes
Why Batch Submission Is the Right Default
The shell prompt on the Sagehen HPC login node is convenient but not where your real work belongs. Login nodes are shared and intentionally constrained: a long calculation on the login node steals resources from every other user trying to edit, transfer, or schedule. Batch submission moves your work to the compute partition where SLURM can give it dedicated CPU, memory, and time, and where your job survives if you close your laptop.
The pattern is consistent: you write a short shell script that
includes both SLURM directives (lines starting with
#SBATCH) and the commands to run, then submit it with
sbatch. SLURM puts the job in queue, runs it when resources
are available, and writes its stdout and stderr to files in your current
directory.
Submitting with sbatch
SLURM responds immediately:
Submitted batch job 12345
Your job ID is 12345. Use this number to track and manage the job. The submitting shell can close, your laptop can sleep, you can disconnect from the VPN, and the job continues to run.
Checking Job Status
BASH
# All your jobs
squeue -u $USER
# A specific job
squeue -j 12345
# Estimated start time for pending jobs
squeue -u $USER --start
Output:
JOBID PARTITION NAME USER ST TIME NODES CPUS
12345 amd analysis alice R 0:23 1 4
Status codes:
-
RRunning: actively executing -
PDPending: waiting for resources, see the REASON field for why -
CGCompleting: cleanup phase, almost done -
CDCompleted: finished successfully -
FFailed: ended with non-zero exit code -
CACancelled: stopped via scancel -
TOTimeout: exceeded--timelimit and was killed
Decoding “why is my job pending?”
squeue -u $USER shows a (REASON) column for
pending jobs:
(Resources): waiting for matching nodes to become
available. Normal for busy partitions; just wait.
(Priority): jobs with higher priority are ahead. This is
fair-share doing its job.
(QOSMaxJobsPerUserLimit): you have hit a per-user
concurrency cap. Wait for one of yours to finish.
(ReqNodeNotAvail): the constraint you set (e.g., a
specific GPU type) currently has no available node. May take a long
time.
(Dependency): job is waiting for another job to complete
(--dependency=afterok:JOBID).
Output Files
By default, SLURM writes a single combined log to
slurm-JOBID.out in the directory where you submitted. For
most workflows, separating stdout and stderr is more useful:
The %j placeholder is replaced by the job ID. Other
useful placeholders: %x for job name, %a for
array task ID, %N for node name. A common pattern that puts
logs in their own folder:
Make sure logs/ exists before submitting. SLURM will
fail to start the job if the output path is invalid.
Viewing Output
BASH
# While running (real-time)
tail -f analysis_12345.out
# After completion
cat analysis_12345.out
# Last 50 lines (useful for long jobs)
tail -50 analysis_12345.out
# Search for a specific string
grep -i error analysis_12345.out
You can also specify a full path so logs land somewhere predictable:
Email Notifications
BASH
#SBATCH --mail-user=alice@pomona.edu
#SBATCH --mail-type=END # When finished
#SBATCH --mail-type=FAIL # On failure
#SBATCH --mail-type=ALL # Any state change (verbose)
Email Best Practices
For testing and short jobs: no email at all. Watch with
squeue instead.
For medium jobs (hours): FAIL only. You will be notified
about problems but not flooded with completion notices.
For long important jobs (days): END,FAIL. You want to
know either way, but only once.
For job arrays: FAIL only. Otherwise a 100-task array
sends 100 completion emails.
The BEGIN mail-type exists but is almost never useful:
by the time the email arrives, your job has already started.
Changing Directory
By default, scripts run in the directory where you submitted. If your
submitted script is in /rhome/alice/scripts/ but your data
is in /rhome/alice/project/, the script’s relative paths
will break.
Two solutions, in order of preference:
BASH
# Option A: cd at the top of the script (clearest)
cd /rhome/alice/project
python analysis.py
# Option B: use absolute paths everywhere (works but verbose)
python /rhome/alice/scripts/analysis.py /rhome/alice/project/data.csv
For jobs that read or write a lot, cd to a directory
under /scratch instead of /rhome (covered in
Workshop 12).
Common Submission Mistakes
A few mistakes show up over and over in real submissions:
Forgetting --time. The default is short. A long job
submitted without an explicit time limit will be killed mid-run.
Setting --mem to the maximum because you do not know
what the job needs. This makes the job harder to schedule. Run a short
test first with seff JOBID to right-size memory.
Mixing tabs and spaces in the SLURM directives. Some directives parse silently incorrectly. Stick to spaces.
Forgetting to load required modules inside the script. The login-node
environment does not carry over. Always include
module load miniconda3 (or whatever you need) at the top of
the script.
Submitting from /scratch. Output files go to the
submission directory. Submit from /rhome so logs persist
after the job’s scratch is cleaned.
Challenge 1: Submit and Monitor a Batch Job
-
Create
analysis.py: -
Create
run_analysis.sh: Submit:
sbatch run_analysis.shCheck status:
squeue -u $USERView output:
cat analysis_JOBID.outAfter completion, run
seff JOBIDto see actual CPU and memory usage.
After submission, squeue shows the job briefly. The
output file contains the computation result and timing. The
seff JOBID output reveals you over-requested memory: a sum
of 10 million integers needs about 50 MB, not 2 GB. On the next run,
drop --mem to 512M. This iteration is exactly
how you tune SLURM scripts: submit, watch, measure with
seff, adjust.
Challenge 2: Read a Pending Job
A friend submitted a job 30 minutes ago and it is still pending. They
run squeue -u $USER and see:
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
54321 gpu big_train bob PD 0:00 1 (Resources)
Explain in plain English what the REASON column means and one thing they could do.
(Resources) means the GPU partition has no node
currently available that matches the job’s requirements. SLURM is just
waiting for a GPU node to free up.
Two reasonable responses: wait it out (queues clear naturally), or
run squeue -p gpu --start to see estimated start times for
all pending GPU jobs and decide if it is worth waiting. If the job needs
an A100 specifically, switching to --gres=gpu:l40s:1 or
--gres=gpu:l40s:1 will likely start sooner because those
GPUs are less oversubscribed.
- Submit batch jobs with
sbatch script.sh; the returned ID is how you track everything later - Status codes: R (running), PD (pending), CG (completing), CD (done), F (failed), TO (timeout)
- The
(REASON)column for pending jobs tells you why they are not running yet - Output files use
--outputand--errordirectives;%jand%xsubstitute job ID and name - Use
tail -fto watch output in real-time while a job runs - Email:
FAILfor medium jobs,END,FAILfor long ones, nothing for tests,FAILonly for arrays - Always run
seff JOBIDafter completion to right-size future submissions - You can log out after submission; jobs run unattended