SLURM Eventos
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