Skip to content

Commit 71bb032

Browse files
authored
Merge pull request #165 from ljwoodley/monitor_job_runs
Monitor failed job runs
2 parents a6b29e2 + 1ec989d commit 71bb032

File tree

7 files changed

+122
-3
lines changed

7 files changed

+122
-3
lines changed

R/logging.R

+2-2
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ write_info_log_entry <- function(conn, target_db_name, table_written = NULL, df,
641641
#' @param email_from The email addresses of the sender
642642
#' @param df_to_email (Optional) A dataframe or a list of dataframes to be included as file attachment(s). If this parameter is used, `file_name` must also be specified.
643643
#' Each dataframe in the list must have a corresponding file name in the `file_name` parameter to ensure a one-to-one match between dataframes and file names.
644-
#' @param file_name (Optional) A character vector specifying the file name(s) of the attachment(s). Valid file extensions are `.csv`, `.xlsx`, and `.zip`. Each file name must be unique.
644+
#' @param file_name (Optional) A character vector specifying the file name(s) of the attachment(s). Valid file extensions are `.csv`, `.xlsx`, `.zip` and, `.txt`. Each file name must be unique.
645645
#' @param ... Additional arguments passed directly to the file writing functions: `write.csv` for CSV files, and `writexl::write_xlsx` for XLSX files.
646646
#'
647647
#' @return No returned value. It performs an action by sending an email.
@@ -783,7 +783,7 @@ send_email <-
783783
}
784784
}
785785

786-
if (file_extension == "zip" &&
786+
if ((file_extension == "zip" || file_extension == "txt") &&
787787
!file.copy(file_name[[i]], output_dir, overwrite = TRUE)) {
788788
stop(paste("Failed to move", file_name[[i]]))
789789
}

etl/run_etl.R

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
library(redcapcustodian)
2+
library(dotenv)
3+
library(callr)
4+
library(argparse)
5+
6+
set_script_run_time()
7+
8+
parser <- ArgumentParser()
9+
parser$add_argument("script_name", help="Script to be run")
10+
parser$add_argument("optional_args", nargs='*', help="Zero or more optional arguments of any type")
11+
12+
if (!interactive()) {
13+
args <- parser$parse_args()
14+
} else {
15+
args <- parser$parse_args(
16+
c(
17+
"study_template/etl/test_failure_alert.R",
18+
"test",
19+
"another test"
20+
)
21+
)
22+
}
23+
24+
script_name <- args$script_name
25+
optional_args <- args$optional_args
26+
27+
if(!fs::file_exists(script_name)) {
28+
stop(sprintf("Specified file, %s, does not exist", script_name))
29+
}
30+
31+
tryCatch({
32+
if (length(optional_args) == 0) {
33+
rscript(script = script_name, stderr = "log.txt")
34+
} else {
35+
rscript(script = script_name, cmdargs = optional_args, stderr = "log.txt")
36+
}
37+
}, error = function(e) {
38+
email_body <- "See the attached log for error details."
39+
script_path <- paste(basename(getwd()), script_name, sep = "/")
40+
email_subject <- paste0("Failed | ", script_path, " | ", format(get_script_run_time(), "%Y-%m-%d"))
41+
file_name = "log.txt"
42+
43+
send_email(email_body = email_body, email_subject = email_subject, file_name = file_name)
44+
})
45+
46+
47+

etl/test_failure_alert.R

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
print("Hello, example host!")
2+
3+
args <- commandArgs(trailingOnly = TRUE)
4+
5+
# Test that the command line args are read
6+
print(paste0("This is a ", args[1]))
7+
print(paste0("This is ", args[2]))
8+
9+
# This will fail as test.csv does not exist.
10+
read.csv("test.csv")
11+

man/send_email.Rd

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Test email alert on script failure
2+
0 0 1 * * root /usr/bin/docker run --rm --env-file /rcc/study_template/.env rcc.site Rscript etl/run_etl.R etl/test_failure_alert.R test "another test"
3+

study_template/etl/run_etl.R

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
library(redcapcustodian)
2+
library(dotenv)
3+
library(callr)
4+
library(argparse)
5+
6+
set_script_run_time()
7+
8+
parser <- ArgumentParser()
9+
parser$add_argument("script_name", help="Script to be run")
10+
parser$add_argument("optional_args", nargs='*', help="Zero or more optional arguments of any type")
11+
12+
if (!interactive()) {
13+
args <- parser$parse_args()
14+
} else {
15+
args <- parser$parse_args(
16+
c(
17+
"study_template/etl/test_failure_alert.R",
18+
"test",
19+
"another test"
20+
)
21+
)
22+
}
23+
24+
script_name <- args$script_name
25+
optional_args <- args$optional_args
26+
27+
if(!fs::file_exists(script_name)) {
28+
stop(sprintf("Specified file, %s, does not exist", script_name))
29+
}
30+
31+
tryCatch({
32+
if (length(optional_args) == 0) {
33+
rscript(script = script_name, stderr = "log.txt")
34+
} else {
35+
rscript(script = script_name, cmdargs = optional_args, stderr = "log.txt")
36+
}
37+
}, error = function(e) {
38+
email_body <- "See the attached log for error details."
39+
script_path <- paste(basename(getwd()), script_name, sep = "/")
40+
email_subject <- paste0("Failed | ", script_path, " | ", format(get_script_run_time(), "%Y-%m-%d"))
41+
file_name = "log.txt"
42+
43+
send_email(email_body = email_body, email_subject = email_subject, file_name = file_name)
44+
})
45+
46+
47+
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
print("Hello, example host!")
2+
3+
args <- commandArgs(trailingOnly = TRUE)
4+
5+
# Test that the command line args are read
6+
print(paste0("This is a ", args[1]))
7+
print(paste0("This is ", args[2]))
8+
9+
# This will fail as test.csv does not exist.
10+
read.csv("test.csv")
11+

0 commit comments

Comments
 (0)