Some time ago, I needed to run some R scripts with different R versions. The solution was to define a function to execute the Rscript for the given R version:

# pseudocode
run_script_bg <- function(script_path, r_version_string) {
  # rscript_binary automatically determined based on r_version_string
  system2(command = rscript_binary, args = script_path)

This worked - until it didn't. Or it least it looked like it didn't. 

There was a little script, let's call it acall.R, which basically looked like this:

foo <- function() {
  cli::cat_line("a start")
  cli::cat_line("sleep 1")
  cli::cat_line("sleep 2")
  cli::cat_line("a finish")

the_process <- callr::r_bg(
  func = foo,
  args = list()

So just an R script, using callr::r_bg to execute a long executing function in the background. The problem was, the function looked like it was never called, i.e.

Rscript acall.R

never wrote anything in /tmp/delme.log.

It took me (shame on me) a while to realise what's going on. Here is what I learned, maybe somebody else will also find it useful.

callr::r_bg starts a process (from the package processx) in the background. As I've learned from here , these processes are finalized (and killed) automatically if the corresponding process object goes out of scope, as soon as the object is garbage collected by R.

In my understanding, Rscript starts an R session, runs the script which starts a process, then the R session is stopped and the R process is immediately killed.
You can easily check this if you add the following lines to the script:

running_time_sec <- 0

while (running_time_sec < 5) {
  running_time_sec <- running_time_sec + 1

This results is:

rscript callr max running time

Of course, what you actually need is to keep the R session alive as long as it is necessary:

#running_time_sec <- 0
# while (running_time_sec < 5) {
#         Sys.sleep(1)
#         running_time_sec <- running_time_sec + 1
# }

while (the_process$is_alive()) {

This results in:

rscript callr alive

This also means that my  run_script_bg function is fragile, since it won't give the expected results if the input script uses processes from the processx package.
I did not find a way to deal with this, in an ideal world I would warn the user that things might not work as expected if processes are used, but I don't know an easy way to do this. If you have a suggestion, let me know.

Make a promise. Show up. Do the work. Repeat.