4
$\begingroup$

I wrote a SLURM job script to run a computational chemistry calculation using the CREST program (part of the xtb software package). In the script, I create a temporary directory on the local storage of the compute node. The files from the submission directory are copied to this temporary directory, after which I run the CREST calculation in the background. The script contains a trap to handle SIGTERM signals (for job termination). If terminated, it attempts to archive results and copy the archive back to the original submission directory.

The functions are:

  • wait_for_allocated_time: Calculates and waits for the job's time limit
  • report_crest_status: Reports the status of the CREST calculation
  • archiving: Creates an archive of the output files
  • handle_sigterm: Handles premature job termination

The script is designed to:

  • Utilize local storage on compute nodes for better I/O performance
  • Handle job time limits gracefully
  • Attempt to save results even if the job is terminated prematurely
  • Provide detailed logging of the job's progress and any issues encountered

The problem with the script is that it fails to create an archive because sometimes the local directory is cleaned up before archiving can occur (see output below).

  • Running xtb crest calculation...
  • xtb crest calculation interrupted. Received SIGTERM signal. Cleaning up...
  • Sat Jul 6 16:24:20 CEST 2024: Creating output archive...
  • Sat Jul 6 16:24:20 CEST 2024: LOCAL_DIR /tmp/job-11235125
  • total 0
  • Sat Jul 6 16:24:20 CEST 2024: ARCHIVE_PATH /tmp/job-11235125/output-11235125.tar.gz
  • tar: Removing leading `/' from member names
  • tar: /tmp/job-11235125: Cannot stat: No such file or directory
  • tar (child): /tmp/job-11235125/output-11235125.tar.gz: Cannot open: No such file or directory
  • tar (child): Error is not recoverable: exiting now
  • tar: Child returned status 2
  • tar: Error is not recoverable: exiting now
  • Sat Jul 6 16:24:20 CEST 2024: Failed to create output archive.
  • Job finished.

I hoped to prevent this by running a parallel process in the background and wait for it to monitor the job's allocated time. This process will sleep until the allocated time is nearly up. Only when the archiving took place, the complete job script will end and thus preventing the clean up of the local directory. However, somehow this did not work and I do not know how to prevent cleanup of the local directory in case of termination/cancellation/error of the job.

Can someone help me?

#!/bin/bash

dos2unix $1
dos2unix *

pwd=$(pwd)
#echo "0) Submitting SLURM job..." >> "$pwd/output.log"

#SBATCH --time=0-00:30:00
#SBATCH --partition=regular
#SBATCH --nodes=1
#SBATCH --ntasks=12
#SBATCH --cpus-per-task=1
#SBATCH --mem=2G

module purge
module load OpenMPI

LOCAL_DIR="$TMPDIR/job-${SLURM_JOBID}"

SIGTERM_RECEIVED=0

function wait_for_allocated_time () {
    local start_time=$(date +%s)
    local end_time
    local time_limit_seconds
    
    time_limit_seconds=$(scontrol show job $SLURM_JOB_ID | grep TimeLimit | awk '{print $2}' | 
        awk -F: '{ if (NF==3) print ($1 * 3600) + ($2 * 60) + $3; else print ($1 * 60) + $2 }')
    end_time=$((start_time + time_limit_seconds))
    
    echo "Job started at: $(date -d @$start_time)" >> "$pwd/time.log"
    echo "Expected end time: $(date -d @$end_time)" >> "$pwd/time.log"
    echo "Job time limit: $((time_limit_seconds / 60)) minutes" >> "$pwd/time.log"
    
    current_time=$(date +%s)
    sleep_duration=$((end_time - current_time))
    
    if [ $sleep_duration -gt 0 ]; then
        echo "Sleeping for $sleep_duration seconds..." >> "$pwd/time.log"
        sleep $sleep_duration
        echo "Allocated time has ended at: $(date)" >> "$pwd/time.log"
    else
        echo "Job has already exceeded its time limit." >> "$pwd/time.log"
    fi
}

function report_crest_status () {
    local exit_code=$1
    if [ $SIGTERM_RECEIVED -eq 1 ]; then
        echo "xtb crest calculation interrupted. Received SIGTERM signal. Cleaning up..." >> "$pwd/output.log"
    elif [ $exit_code -eq 0 ]; then
        echo "xtb crest calculation completed successfully." >> "$pwd/output.log"
    else
        echo "xtb crest calculation failed or was terminated. Exit code: $exit_code" >> "$pwd/output.log"
    fi
}

function archiving () {
    echo "$(date): Creating output archive..." >> "$pwd/output.log"

    cd "$LOCAL_DIR" >> "$pwd/output.log" 2>&1
    echo "$(date): LOCAL_DIR $LOCAL_DIR" >> "$pwd/output.log"
    ls -la >> "$pwd/output.log" 2>&1
    
    ARCHIVE_NAME="output-${SLURM_JOBID}.tar.gz"
    ARCHIVE_PATH="$LOCAL_DIR/$ARCHIVE_NAME"
    echo "$(date): ARCHIVE_PATH $ARCHIVE_PATH" >> "$pwd/output.log"
    
    tar cvzf "$ARCHIVE_PATH" --exclude=output.log --exclude=slurm-${SLURM_JOBID}.out $LOCAL_DIR >> "$pwd/output.log" 2>&1
    if [ -f "$ARCHIVE_PATH" ]; then
        echo "$(date): Output archive created successfully." >> "$pwd/output.log"
    else
        echo "$(date): Failed to create output archive." >> "$pwd/output.log"
        return 1
    fi
    
    echo "$(date): Copying output archive to shared storage..." >> "$pwd/output.log"
    cp "$ARCHIVE_PATH" "$pwd/" >> "$pwd/output.log" 2>&1
    if [ $? -eq 0 ]; then
        echo "$(date): Output archive copied to shared storage successfully." >> "$pwd/output.log"
    else
        echo "$(date): Failed to copy output archive to shared storage." >> "$pwd/output.log"
    fi
}

function handle_sigterm () {
    SIGTERM_RECEIVED=1
    report_crest_status 1
    archiving
    kill $SLEEP_PID
}

trap 'handle_sigterm' SIGTERM #EXIT #USR1

echo "1) Creating temporary directory $LOCAL_DIR on node's local storage..." >> "$pwd/output.log"
mkdir -p "$LOCAL_DIR" >> "$pwd/output.log" 2>&1
if [ $? -eq 0 ]; then
    echo "Temporary directory created successfully." >> "$pwd/output.log" 
else
    echo "Failed to create temporary directory." >> "$pwd/output.log"
    exit 1
fi

echo "2) Copying files from $pwd to temporary directory..." >> "$pwd/output.log"
cp "$pwd"/* "$LOCAL_DIR/" >> "$pwd/output.log" 2>&1
if [ $? -eq 0 ]; then
    echo "Files copied successfully." >> "$pwd/output.log"
else
    echo "Failed to copy files." >> "$pwd/output.log"
    exit 1
fi

cd "$LOCAL_DIR" || exit 1

echo "3) Running xtb crest calculation..." >> "$pwd/output.log"
srun crest Bu-Em_RR_OPT.xyz --T 12 --sp > crest.out &
MAIN_PID=$!

wait_for_allocated_time &
SLEEP_PID=$!

wait $MAIN_PID #wait -n $MAIN_PID $SLEEP_PID
CREST_EXIT_CODE=$?

if [ $SIGTERM_RECEIVED -eq 0 ]; then
    report_crest_status $CREST_EXIT_CODE
    if [ $CREST_EXIT_CODE -eq 0 ]; then
        archiving
    fi
    kill $SLEEP_PID
fi

wait $SLEEP_PID
echo "Job finished." >> "$pwd/output.log"
$\endgroup$
1
  • $\begingroup$ +1 but please make your title more specific and clear. It's often better if it's an actual question ending in a question mark. $\endgroup$ Commented Jul 6 at 18:24

1 Answer 1

1
$\begingroup$

On line 62 (cd "$LOCAL_DIR" >> "$pwd/output.log" 2>&1) you change directory into your temp directory immediately before beginning the archive on line 70. Unless your script got extremely unlucky and the temporary directory was removed between these lines, the directory is still there on line 70 (otherwise you would have got an error earlier from line 62).

I can't recreate your exact issue on my system, but there are two problems with how you are constructing your archive that you should fix before debugging further (to rule them out as possible causes).

Firstly, you are using absolute (starting with a '/') path names for the contents of the archive. This is not recommended for a few reasons, mostly because it will recreate a strange folder structure when you later unpack the archive, and is the origin of this warning in your output: tar: Removing leading '/' from member names. If your version of tar is bugged, I wonder if this might cause the missing file error (because tar is changing the given file names), not sure.

Secondly, and perhaps more importantly, you are trying to place the new archive inside the folder you are compressing. This is not possible, as it would result in a recursive archive (the archive would contain itself).

You can resolve these issues fairly easily. Instead of creating the archive and then immediately copying it, why not just write the new archive directly to your starting directory? Likewise, you've already changed directory into the folder you want to archive. You can just give the current directory (.) as input:

tar -cvzf "$pwd/$ARCHIVE_NAME" --exclude=output.log --exclude=slurm-${SLURM_JOBID}.out . >> "$pwd/output.log" 2>&1
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .