SLURM Eventos

De NLHPC

Gatillando un proceso cuando termina un trabajo

Por Juan Carlos Maureira

En linux un proceso cuando termina emite (o recibe) una señal de término (pudiendo ser enviada por el S.O. o manualmente por el usuario). Las señales de término pueden dar luces sobre cómo termina un proceso y dependiendo de esto, se pueden manejar distintos escenarios. Lo anterior podría ser útil, por ejemplo, para limpiar o restaurar los recursos utilizados por un script despachado por SLURM,

Para lo anterior se describen dos opciones. La primera manejando eventos con SLURM (predefinidos por este) y la otra controlando las señales de terminación del trabajo manejadas a nivel del sistema operativo las cuales pueden ser procesadas por el mismo script de ejecución que se utiliza con SLURM.

Los pro y contras de cada alternativa se exponen a continuación con ejemplos de código incluidos:

Por manejo de eventos en SLURM

En este caso, el trabajo principal es enviado mediante una función intermediaria (submit_c como aparece más adelante en el código fuente de ejemplo) la cual crea dos trabajos dependientes (PONER LINK A MAS INFO EN EL MAN DE sbatch); una ejecutada cuando el trabajo principal termina con un exit code distinto de cero (afternotok dependency directive), y la otra se ejecuta cuando el trabajo termina con un código de salida igual a 0 (afterok dependency directive).

Dependiendo del caso, la función que se ejecute debe cancelar su alterna. Dicho de otro modo, si el script principal termina bien su ejecución, entonces se debe ejecutar la directiva afterok y cancelar el trabajo que se ejecutaría con la directiva afternotok y de forma recíproca si es que el trabajo principal terminara de mala forma.

El problema con este enfoque es que no existe la garantía de que la tarea dependiente se ejecute en el mismo nodo que la tarea principal, por lo que no sería una buena alternativa para realizar tareas de limpieza, por ejemplo.

Adicionalmente, no hay forma de diferenciar cuando el script principal termina con una señal distinta de 0 o si fue cancelada con el comando scancel o qdel.

 #!/bin/bash
 # 
 # Test for trigger a job on cancel a main job
 # or cancel that job on normal termination of the 
 # main job 
 #
 # (c) 2016 - Juan Carlos Maureira
 # (c) 2016 - Center for Mathematical Modeling
 
 SUBMIT_BIN="sbatch"
 CANCEL_BIN="scancel"
 
 MAIN_JOB="main_job.q"
 CANCEL_JOB="cancel_job.q"
 
 function submit_c() {
 
     local OPTIND opt main_job cancel_job submit_args
 
      while getopts ":a:c:j:" o; do
         case "${o}" in
             a)
                 submit_args="${OPTARG}"
                 ;;
             c)
                 cancel_job="${OPTARG}"
                 ;;
             j)
                 main_job="${OPTARG}"
                 ;;
         esac
     done
     shift $((OPTIND-1))
 
     args="$@"
  
     MAIN_SUBMIT_OUTPUT=`${SUBMIT_BIN} $submit_args $main_job $args`
     if [ $? -eq 0 ]; then
         MAIN_JOB_ID=`echo $MAIN_SUBMIT_OUTPUT | cut -f 4 -d" "`
         export JOB_ID=$MAIN_JOB_ID
 
         CANCEL_SUBMIT_OUTPUT=`${SUBMIT_BIN} -d afternotok:$MAIN_JOB_ID $cancel_job cancel $MAIN_JOB_ID`
         CANCEL_JOB_ID=`echo $CANCEL_SUBMIT_OUTPUT | cut -f 4 -d" "`
         echo "$CANCEL_JOB_ID" > .$MAIN_JOB_ID.cancel
 
         SUCCESS_SUBMIT_OUTPUT=`${SUBMIT_BIN} -d afterok:$MAIN_JOB_ID $cancel_job success $MAIN_JOB_ID`
         SUCCESS_JOB_ID=`echo $SUCCESS_SUBMIT_OUTPUT | cut -f 4 -d" "`
         echo "$SUCCESS_JOB_ID" > .$MAIN_JOB_ID.success
 
         return 0
     fi
     return 1
 }
 
 echo "submiting main job"
 submit_c -c $CANCEL_JOB -j $MAIN_JOB arg1 arg2 arg3
 MAIN_JOB_ID=$JOB_ID
 echo "main job id : $MAIN_JOB_ID"

Por manejo de señales del S.O.

Este enfoque, por otro lado, utiliza la utilidad trap de linux (en bash), por lo tanto es posible ejecutar ciertas funciones al registrar las señales adecuadas. Esta forma es ideal para ejecutar tareas de limpieza o restablecer estados anteriores independientemente de cómo termine el script ya que la ejecución de la función será siempre en el mismo nodo que se ejecutó la tarea principal. De hecho, la ejecución de la función de limpieza es parte del trabajo principal (antes de que termine). En el caso de SLURM, el comando scancel envía una señal TERM al script antes de enviar la señal la señal KILL. Por lo tanto, la cancelación por comando puede ser capturada de cualquier forma que termine el script.

 #!/bin/bash
 
 #SBATCH -J signal_trap_cancel
 
 function s_term {
     echo "job terminated"
     #exit 0
 }
 
 function s_kill {
     echo "job killed"
     exit 1
 }
 
 trap "s_term" SIGTERM
 trap "s_kill" SIGKILL
 
 echo "pid is $$"
 
 echo "doing something for 60 seconds"
 sleep 60
 
 exit 0