% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/batchtools_slurm.R
\name{batchtools_slurm}
\alias{batchtools_slurm}
\title{A batchtools Slurm backend resolves futures in parallel via a Slurm job scheduler}
\usage{
batchtools_slurm(
  ...,
  template = "slurm",
  scheduler.latency = 1,
  fs.latency = 65,
  resources = list(),
  delete = getOption("future.batchtools.delete", "on-success"),
  workers = getOption("future.batchtools.workers", default = 100L)
)
}
\arguments{
\item{template}{(optional) Name of job-script template to be searched
for by \code{\link[batchtools:findTemplateFile]{batchtools::findTemplateFile()}}. If not found, it defaults to
the \code{templates/slurm.tmpl} part of this package (see below).}

\item{scheduler.latency}{[\code{numeric(1)}]\cr
Time to sleep after important interactions with the scheduler to ensure a sane state.
Currently only triggered after calling \code{\link[batchtools]{submitJobs}}.}

\item{fs.latency}{[\code{numeric(1)}]\cr
Expected maximum latency of the file system, in seconds.
Set to a positive number for network file systems like NFS which enables more robust (but also more expensive) mechanisms to
access files and directories.
Usually safe to set to \code{0} to disable the heuristic, e.g. if you are working on a local file system.}

\item{resources}{(optional) A named list passed to the \pkg{batchtools}
job-script template as variable \code{resources}. This is based on how
\code{\link[batchtools:submitJobs]{batchtools::submitJobs()}} works, with the exception for specially
reserved names defined by the \pkg{future.batchtools} package;
\itemize{
\item \code{resources[["details"]]}, if TRUE, results in the job script outputting
job details and job summaries at the beginning and at the end.
\item \code{resources[["startup"]]} and \code{resources[["shutdown"]]} are character
vectors of shell code to be injected to the job script as-is.
\item \code{resources[["modules"]]} is character vector of Linux environment
modules to be loaded.
\item \code{resources[["envs"]]}, is an optional names character vector specifying
environment variables to be set.
\item \code{resources[["rscript"]]} is an optional character vector specifying
how the 'Rscript' is launched. The \code{resources[["rscript_args"]]} field
is an optional character vector specifying the 'Rscript' command-line
arguments.
\item \code{resources[["asis"]]} is a character vector that are passed as-is to
the job script and are injected as job resource declarations.
\item All remaining \code{resources} named elements are injected as named resource
specification for the scheduler.
}}

\item{delete}{Controls if and when the batchtools job registry folder is
deleted.
If \code{"on-success"} (default), it is deleted if the future was resolved
successfully \emph{and} the expression did not produce an error.
If \code{"never"}, then it is never deleted.
If \code{"always"}, then it is always deleted.}

\item{workers}{The maximum number of workers the batchtools backend may
use at any time, which for HPC schedulers corresponds to the maximum number
of queued jobs. The default is
\code{getOption("\link{future.batchtools.workers}", 100)}.}

\item{\ldots}{Not used.}
}
\value{
Nothing.
}
\description{
A batchtools Slurm backend resolves futures in parallel via a Slurm job scheduler
}
\details{
Batchtools Slurm futures use \pkg{batchtools} cluster functions
created by \code{\link[=makeClusterFunctionsSlurm2]{makeClusterFunctionsSlurm2()}}, which are used
to interact with the Slurm job scheduler. This requires that Slurm
commands \code{sbatch}, \code{squeue}, \code{sacct}, and \code{scancel} are available on
the current machine.

The default template script \code{templates/slurm.tmpl} can be found in:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{system.file("templates", "slurm.tmpl", package = "future.batchtools")
}\if{html}{\out{</div>}}

and comprises:

\if{html}{\out{<div class="sourceCode bash">}}\preformatted{#!/bin/bash
######################################################################
# A batchtools launch script template for Slurm
#
# Author: Henrik Bengtsson 
######################################################################

## Job name
#SBATCH --job-name=<\%= job.name \%>
## Direct streams to logfile
#SBATCH --output=<\%= log.file \%>

## Resources needed
<\%
  ## Should scheduler "details" be seen?
  details <- isTRUE(resources[["details"]])
  resources[["details"]] <- NULL

  ## Shell "startup" code to evaluate
  startup <- resources[["startup"]]
  resources[["startup"]] <- NULL
     
  ## Shell "shutdown" code to evaluate
  shutdown <- resources[["shutdown"]]
  resources[["shutdown"]] <- NULL
     
  ## Environment modules specifications
  modules <- resources[["modules"]]
  resources[["modules"]] <- NULL
  
  ## Environment variables to be set
  envs <- resources[["envs"]]
  if (length(envs) > 0) \{
    stopifnot(is.character(envs), !is.null(names(envs)))
  \}
  resources[["envs"]] <- NULL
     
  ## Custom "Rscript" command and Rscript arguments
  rscript <- resources[["rscript"]]
  if (is.null(rscript)) \{
    rscript <- "Rscript"
  \} else if (length(rscript) == 0 || !nzchar(rscript)[1]) \{
    stop("Argument 'resources' specifies an empty 'rscript' field")
  \}
  resources[["rscript"]] <- NULL
  rscript_args <- resources[["rscript_args"]]
  resources[["rscript_args"]] <- NULL
  rscript_call <- paste(c(rscript, rscript_args), collapse = " ")
    
  ## As-is resource specifications
  job_declarations <- resources[["asis"]]
  resources[["asis"]] <- NULL
    
  ## Remaining resources are assumed to be of type '<key>=<value>'
  opts <- unlist(resources, use.names = TRUE)
  opts <- sprintf("\%s=\%s", names(opts), opts)
  job_declarations <- sprintf("#SBATCH \%s", c(job_declarations, sprintf("--\%s", opts)))
  writeLines(job_declarations)
\%>

## Bash settings
set -e          # exit on error
set -u          # error on unset variables
set -o pipefail # fail a pipeline if any command fails
trap 'echo "ERROR: future.batchtools job script failed on line $LINENO" >&2; exit 1' ERR

<\% if (length(job_declarations) > 0) \{
  writeLines(c(
    "echo 'Job submission declarations:'",
    sprintf("echo '\%s'", job_declarations),
    "echo"
  ))
\} \%>

<\% if (details) \{ \%>
if command -v scontrol > /dev/null; then
  echo "Job information:"
  scontrol show job "$\{SLURM_JOB_ID\}"
  echo
fi
<\% \} \%>

<\% if (length(startup) > 0) \{
  writeLines(startup)
\} \%>

<\% if (length(modules) > 0) \{
  writeLines(c(
    "echo 'Load environment modules:'",
    sprintf("echo '- modules: \%s'", paste(modules, collapse = ", ")),
    sprintf("module load \%s", paste(modules, collapse = " ")),
    "module list"
  ))
\} \%>

<\% if (length(envs) > 0) \{
  writeLines(c(
    sprintf("echo 'Setting environment variables: [n=\%d]'", length(envs)),
    sprintf("echo ' - \%s=\%s'", names(envs), shQuote(envs)),
    sprintf("export \%s=\%s", names(envs), shQuote(envs))
  ))
\} \%>

echo "Session information:"
echo "- timestamp: $(date +"\%Y-\%m-\%d \%H:\%M:\%S\%z")"
echo "- hostname: $(hostname)"
echo "- Rscript call: <\%= rscript_call \%>"
if ! command -v <\%= rscript[1] \%> &> /dev/null; then
    >&2 echo "ERROR: Argument 'resources' specifies a non-existing 'Rscript' launch command: <\%= rscript[1] \%>. Maybe you need to specify which environment modules to load in the 'resources' argument, e.g. 'plan(future.batchtools::batchtools_slurm, resources = list(modules = c(\\"r\\")))'. The search PATH for '\%<= rscript[1] \%>' was $\{PATH\}"
    exit 1
fi
echo "- Rscript version: $(<\%= paste(rscript, collapse = " ") \%> --version)"
echo "- R_LIBS_USER=$\{R_LIBS_USER:-<not set>\}"
echo "- R_LIBS_SITE=$\{R_LIBS_SITE:-<not set>\}"
echo "- R_LIBS=$\{R_LIBS:-<not set>\}"
echo "- Rscript library paths: $(<\%= rscript_call \%> -e "cat(shQuote(.libPaths()), sep = ' ')")"
echo

## Launch R and evaluate the batchtools R job
echo "Calling 'batchtools::doJobCollection()' ..."
echo "- job name: '<\%= job.name \%>'"
echo "- job log file: '<\%= log.file \%>'"
echo "- job uri: '<\%= uri \%>'"
<\%= rscript_call \%> -e 'batchtools::doJobCollection("<\%= uri \%>")'
res=$?
echo " - exit code: $\{res\}"
echo "Calling 'batchtools::doJobCollection()' ... done"
echo

<\% if (details) \{ \%>
if command -v sstat > /dev/null; then
  echo "Job summary:"
  sstat --format="JobID,AveCPU,MaxRSS,MaxPages,MaxDiskRead,MaxDiskWrite" --allsteps --jobs="$\{SLURM_JOB_ID\}"
fi
<\% \} \%>

<\% if (length(shutdown) > 0) \{
  writeLines(shutdown)
\} \%>

echo "End time: $(date +"\%Y-\%m-\%d \%H:\%M:\%S\%z")"

## Relay the exit code from Rscript
exit "$\{res\}"
}\if{html}{\out{</div>}}

This template and the built-in \code{\link[=makeClusterFunctionsSlurm2]{makeClusterFunctionsSlurm2()}}
have been verified to work on a few different Slurm HPC clusters;
\enumerate{
\item Slurm 21.08.4, Rocky Linux 8, NFS global filesystem (September 2025)
\item Slurm 22.05.10, Rocky Linux 9, Lustre global filesystem (September 2025)
\item Slurm 22.05.11, Rocky Linux 8, NFS global filesystem (September 2025)
\item Slurm 23.02.6, Ubuntu 24.04 LTS, NFS global filesystem (September 2025)
\item Slurm 24.11.3, AlmaLinux 9, Lustre global filesystem (September 2025)*
\item Slurm 24.11.5, Rocky Linux 9, VAST global filesystem (February 2026)
}

(*) Verified with \strong{future.batchtools} 0.20.0, which used
\code{\link[batchtools:makeClusterFunctionsSlurm]{batchtools::makeClusterFunctionsSlurm()}}, which the new
\code{\link[=makeClusterFunctionsSlurm2]{makeClusterFunctionsSlurm2()}} enhances.
}
\examples{
\dontshow{if (interactive()) withAutoprint(\{ # examplesIf}
library(future)

# Limit runtime to 10 minutes and memory to 400 MiB per future,
# request a parallel environment with four slots on a single host.
# Submit to the 'freecycle' partition. Load environment modules 'r' and
# 'jags'. Report on job details at startup and at the end of the job.
plan(future.batchtools::batchtools_slurm, resources = list(
  time = "00:10:00", mem = "400M",
  asis = c("--nodes=1", "--ntasks=4", "--partition=freecycle"),
  modules = c("r", "jags"),
  details = TRUE
))

f <- future({
  data.frame(
     hostname = Sys.info()[["nodename"]],
           os = Sys.info()[["sysname"]],
    osVersion = utils::osVersion,
        cores = unname(parallelly::availableCores())
  )
})
info <- value(f)
print(info)

# As above, but use R from the Rocker 'r-base' Linux container;
#
#   mkdir -p ~/lxc
#   apptainer build ~/lxc/rocker_r-base.sif docker://rocker/r-base
#
# Example assumes that 'future.batchtools' has already been installed in
# the container to the 'R_LIBS_USER' package folder living on the host;
#
#   R_LIBS_USER=~/R/rocker-\%p-library/\%v ~/lxc/rocker_r-base.sif
#   ...
#   > chooseCRANmirror(ind = 1)
#   > install.packages("future.batchtools")
#
plan(future.batchtools::batchtools_slurm, resources = list(
  time = "00:10:00", mem = "400M",
  asis = c("--nodes=1", "--ntasks=4", "--partition=freecycle"),
  details = TRUE,
  envs = c(R_LIBS_USER = "~/R/rocker-\%p-library/\%v"),
  rscript = c("apptainer", "exec", "~/lxc/rocker_r-base.sif", "Rscript")
))

f <- future({
  data.frame(
     hostname = Sys.info()[["nodename"]],
           os = Sys.info()[["sysname"]],
    osVersion = utils::osVersion,
        cores = unname(parallelly::availableCores()),
      modules = Sys.getenv("LOADEDMODULES")
  )
})
info <- value(f)
print(info)
\dontshow{\}) # examplesIf}
}
\references{
\itemize{
\item \url{https://en.wikipedia.org/wiki/Slurm_Workload_Manager}
}
}
