Starts one task in a process that outlives the R session which started it, and returns at once. The task's exit code is written to a status file when it ends.
Arguments
- task_name
Character string. Name of the task to run.
- package_dir
Character string. Directory of the implementation package, which must hold a
DESCRIPTION. Defaults to".".- ss_prefix
Character string. R expression that resolves to the surveillance system object in the child process. Defaults to
"global$ss".- run_dir
Character string or
NULL. Where to write the log, status and lock files.NULLuses theCS9_RUN_DIRenvironment variable, and~/.cs9/task-runswhen that is unset.
Value
Invisibly, a list with elements task, log,
status, errors and pid, all character strings. The
status and errors files do not exist until the task ends.
Details
This is the non-interactive counterpart to
run_task_sequentially_as_callr_bg_using_load_all(). Use that one
in Positron, where a person watches a live console. Use this one when nobody
is watching: a script, a cron entry, or an agent driving a machine over SSH.
The difference is not style. TaskJob passes
supervise = TRUE, so callr kills the task when the parent R
process exits, and it streams output through later::later(), which
needs an event loop that Rscript does not drive.
Waiting
Wait on the status file, never on the log. A log cannot separate "finished cleanly" from "died at line 4", so a caller reading the tail of a log is guessing. The status file appears only when the task ends, and holds the exit code. No file means still running, never done.
Read the error count as well as the exit code
Exit code 0 does not mean the work succeeded. Measured on 2026-08-17: a
NorSySS import exited 0 with 212 rejected COPY statements in its log,
because the PostgreSQL load_data_infile method runs psql
through system2() without reading its exit status, so a rejected
COPY never reaches R. A status of 0 beside a non-zero error count is
the shape that failure takes.
The count comes from a grep over the log, so it is a heuristic. A count above zero is worth reading. A count of zero does NOT prove the task did what it should: only checking the data can tell you that.
Provenance
The log opens with the task name, the implementation package and its version, the git branch and commit of the package directory when it is a repository, and whether that tree was clean. A log that reports only a duration cannot answer "which code ran" afterwards.
Examples
if (FALSE) { # \dontrun{
run <- run_task_detached("my_task", package_dir = ".")
# later, from anywhere:
readLines(run$status)
} # }
