Nothing
#' Creating Slurm jobs
#'
#' Utilities to deal with objects of class `slurm_job`. The function `new_slurm_job`,
#' which is mostly intended to be for internal used, creates an object of class
#' `slurm_job`. The function `last_submitted_job` returns the last submitted
#' job in the current R session, and the functions `read/write_slurm_job` are
#' utility functions to read and write R jobs respectively.
#'
#' @param call The original call
#' @param rscript,bashfile The R script and bash file path.
#' @param robjects A character vector of R objects that will be imported in the job.
#' @param opts_job,opts_r List. In the case of `opts_job`, a list of parameters
#' passed to [sbatch]. `opts_r` is a list of parameters used within R. Both can
#' be retrieved by [opts_slurmR]`$get_opts_job()` and [opts_slurmR]`$get_opts_r()`
#' respectively.
#' @param njobs Integer. Number of jobs to start (array).
#' @param hooks List of functions. To be called on the collected results after
#' it finalizes.
#' @param x An object of class `slurm_job`.
#' @param ... Further arguments passed to the method.
#' @name slurm_job
NULL
check_hooks <- function(x) {
if (length(x) == 0)
return(invisible())
if (!inherits(x, "list"))
stop(
"The -hooks- parameter should be of class \"list\". It is of class:\n\"",
paste(class(x), collapse = "\", \""),
call. = FALSE
)
test <- !sapply(x, is.function)
if (any(test))
stop(
"The hook(s): ", paste0(which(test), collapse = ", "), " are not ",
"functions. All hooks (if any) should be functions.", call. = FALSE
)
return(invisible())
}
#' @export
#' @details In the case of the function `new_slurm_job`, besides of creating the
#' object of class `slurm_job`, the function calls `write_slurm_job` and stores
#' the job object in an [`rds`][saveRDS] class file. The name and location of
#' the saved rds file is generated using the function `snames("job")`.
#'
#' @rdname slurm_job
#' @return An environment of class `slurm_job`. This has the following items:
#' - `call` The original call ([Slurm_lapply], [Slurm_Map], etc.)
#' - `rscript` The full path to the R script to be executed by bash file.
#' - `bashfile` The full path to the bash file to be executed by [sbatch].
#' - `robjects` Ignored.
#' - `njobs` The number of jobs to be submitted (job array).
#' - `opts_job`,`opts_r` Two lists of options as returned by [opts_slurmR]$get_opts_job()
#' and [opts_slurmR]$get_r_opts() at the moment of the creation of the `slurm_job`.
#' - `hooks` A list of functions to be called on the collected objects
#' by [Slurm_collect].
#'
new_slurm_job <- function(
call,
rscript,
bashfile,
robjects,
njobs,
opts_job,
opts_r,
hooks = NULL
) {
# Checking hooks
check_hooks(hooks)
job <- structure(list2env(
list(
call = call,
rscript = rscript,
bashfile = bashfile,
robjects = NULL,
njobs = njobs,
opts_job = opts_job,
opts_r = opts_r,
jobid = NA_integer_,
hooks = hooks
),
envir = new.env(parent = emptyenv())
), class = "slurm_job"
)
# Storing job in folder
saveRDS(
job,
file = snames(
"job",
tmp_path = opts_r$tmp_path,
job_name = opts_job$`job-name`
),
compress = FALSE
)
return(job)
}
# Job name ---------------------------------------------------------------------
get_job_name <- function(x) UseMethod("get_job_name")
get_job_name.slurm_job <- function(x) x$opts_job$`job-name`
get_job_name.integer <- function(x) {
if (is.na(last_job()$jobid))
stop(
"Cannot get the path for job -", x, "-. You can only call this function ",
"right after submitting a job, or when -x- is of class \'slurm_job\'. ",
"-x- is of class ", class(x),
)
if (last_job()$jobid == x) {
return(get_job_name(last_job()))
}
stop(
"The jobid ", x, " cannot be matched to the last job submitted (id: ",
last_job()$jobid, ".)"
)
}
# Job path ---------------------------------------------------------------------
get_tmp_path <- function(x) UseMethod("get_tmp_path")
get_tmp_path.slurm_job <- function(x) x$opts_r$tmp_path
get_tmp_path.integer <- function(x) {
if (is.na(last_job()$jobid))
stop(
"Cannot get the path for job -", x, "-. You can only call this function ",
"right after submitting a job, or when -x- is of class \'slurm_job\'. ",
"-x- is of class ", class(x),
)
if (last_job()$jobid == x) {
return(get_tmp_path(last_job()))
}
stop(
"The jobid ", x, " cannot be matched to the last job submitted (id: ",
last_job()$jobid, ".)"
)
}
# Getting the job id (Slurm) ---------------------------------------------------
get_job_id <- function(x) UseMethod("get_job_id")
get_job_id.slurm_job <- function(x) x$jobid
`get_job_id<-` <- function(x, value) UseMethod("get_job_id<-")
`get_job_id<-.slurm_job` <- function(x, value) {
if (length(value) != 1L)
stop("Incorrect length for job ID.", call. = FALSE)
value <- as.integer(value)
if (!opts_slurmR$get_debug() && !is.finite(value))
stop("job IDs must be finite. This is the current value trying to assign: ",
value, ".", call. = FALSE)
x$jobid <- value
x
}
get_job_id.slurm_cluster <- function(x) attr(x, "SLURM_JOBID")
get_job_id.slurm_hosts <- function(x) x$jobid
get_job_id.integer <- function(x) {
if (is.na(last_job()$jobid))
stop(
"Cannot get the path for job -", x, "-. You can only call this function ",
"right after submitting a job, or when -x- is of class \'slurm_job\'. ",
"-x- is of class ", class(x),
)
if (last_job()$jobid == x) {
return(x)
}
stop(
"The jobid ", x, " cannot be matched to the last job submitted (id: ",
last_job()$jobid, ".)"
)
}
# Personalized errors
stopifnot_slurm_job <- function(x) {
if (!inherits(x, "slurm_job"))
stop("The passed object is not of class `slurm_job`.", call. = FALSE)
invisible()
}
#' @export
#' @rdname slurm_job
print.slurm_job <- function(x, ...) {
cat("Call:\n", paste(deparse(x$call), collapse="\n"), "\n")
cat(
sprintf("njobs (size) : %i\n", x$njobs),
sprintf("job_name : %s\n", get_job_name(x)),
sprintf("tmp_path : %s\n", get_tmp_path(x)),
"All auxiliray files are located at:\n",
sprintf("\t%s/%s\n", get_tmp_path(x), get_job_name(x)),
sprintf("job ID : %s\n",
ifelse(
is.na(get_job_id(x)),
"Not submitted",
as.character(get_job_id(x))
)
), sep=""
)
if (!is.na(get_job_id(x))) {
print(status(x))
}
invisible(x)
}
#' @rdname slurm_job
#' @param path Character scalar. Path to either a directory with a `job.rds` file,
#' or directly to a `job.rds` file.
#' @export
#' @details The `read_slurm_job` can help the user recovering a previously saved
#' `slurm_job` object. If `path` is a directory, then the function will assume
#' that the file that is looking for lives within that directory and is named
#' `job.rds`. Otherwise, if a file, then it will read it directly. In any case,
#' it will check that the read object is an object of class `slurm_job`.
read_slurm_job <- function(path) {
if (dir.exists(path)) {
path <- normalizePath(file.path(path, "job.rds"))
if (!file.exists(path))
stop(
"The file `job.rds` does not exists in the specified `path`. ",
"Are you sure that folder has a slurm_job object?", call. = FALSE
)
job <- readRDS(path)
} else if (file.exists(path)) {
job <- readRDS(path)
} else
stop(
"Nor a file neither a directory as specified by `path` exists.",
call. = FALSE
)
# After we read the object, we want to make sure that it actually is a
# slurm_job object.
if (!inherits(job, "slurm_job"))
stop("The read object is not of class `slurm_job`.", call. = FALSE)
return(job)
}
#' @rdname slurm_job
#' @export
#' @details The `write_slurm_job` function simply takes a `slurm_job` object
#' and saves it in, if `path` is not specified, whatever the `job$options$chdir`
#' folder is under the name `job.rds`. If a path is specified, the it is directly
#' passed to [saveRDS()].
#' @return In the case of the function `write_slurm_job`, it returns the full
#' path to the file.
write_slurm_job <- function(
x,
path = NULL
) {
stopifnot_slurm_job(x)
# Setting the old ones
if (is.null(path)) {
path <- snames(
"job",
tmp_path = get_tmp_path(x),
job_name = get_job_name(x)
)
}
saveRDS(x, path, compress = FALSE)
invisible(path)
}
#' This environment sets and gets the latest submitted job. The function
#' [last_submitted_job] is a wrapper of it visible to the user.
#' @noRd
LAST_SUBMITTED_JOB <- (function() {
record <- new.env(parent = emptyenv())
record$job <- NULL
record$set <- function(job) {
if (!inherits(job, "slurm_job"))
stop("The `job` argument must be an object of class `slurm_job`.",
call. = FALSE)
record$job <- job
invisible()
}
record$get <- function() {
record$job
}
return(record)
})()
#' @rdname slurm_job
#' @export
#' @details The `las_submitted_job` function will return the latest `slurm_job`
#' object that was submitted via [sbatch] in the current session. The `last_job`
#' function is just an alias of the later. If no job has been submitted, then
#' the resulting value will be `NULL`.
#' @examples
#' \dontrun{
#' # The last_job function can be handy when `plan = "collect"` in a called,
#' # for example
#' job <- Slurm_lapply(1:1000, function(i) runif(100), njobs = 2, plan = "collect")
#'
#' # Post collection analysis
#' status(last_job())
#' }
last_submitted_job <- function() {
LAST_SUBMITTED_JOB$get()
}
#' @export
#' @rdname slurm_job
last_job <- last_submitted_job
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.