From 26ac9887179df9cce34828300972582068721e8e Mon Sep 17 00:00:00 2001 From: pat-s Date: Wed, 17 Jun 2026 19:47:28 +0200 Subject: [PATCH 1/2] fix: recompute package snapshot when missing from cache The install-deps step precomputes pkgs_to_build.rds, r_minor_sensitive_pkgs.rds and s3_cache.rds into /mnt/cache, but that cache volume is per-agent. A build job scheduled on a fresh agent (or racing install-deps) finds the snapshot absent and fails at readRDS. Guard the reads in build-all.R: when any snapshot file is missing, source packages-to-build.R and save the derived files (atomic temp+rename so a concurrent job never reads a half-written rds). The first job on an agent repopulates the shared cache for subsequent jobs; jobs that also miss redo the work. --- local/build-all.R | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/local/build-all.R b/local/build-all.R index 8ce1cd5..f8e8efd 100644 --- a/local/build-all.R +++ b/local/build-all.R @@ -15,6 +15,31 @@ library(bincraft, quietly = TRUE) library(future) plan("sequential") +# The install-deps step precomputes the package snapshot into /mnt/cache, but +# that volume is per-agent: a job landing on a fresh agent (or racing +# install-deps) finds it empty. Recompute the snapshot here when any part is +# missing, so the first job on an agent repopulates the cache for the jobs that +# follow; concurrent jobs that also miss simply redo the work. Write via a +# temp file + atomic rename so a concurrent reader never sees a half-written rds. +package_cache_files <- c( + "/mnt/cache/packages/pkgs_to_build.rds", + "/mnt/cache/packages/r_minor_sensitive_pkgs.rds", + "/mnt/cache/packages/s3_cache.rds" +) +if (!all(file.exists(package_cache_files))) { + message("Package snapshot missing from cache; recomputing via packages-to-build.R") + dir.create("/mnt/cache/packages", showWarnings = FALSE, recursive = TRUE) + save_rds_atomic <- function(obj, path) { + tmp <- paste0(path, ".tmp.", Sys.getpid()) + saveRDS(obj, tmp) + file.rename(tmp, path) + } + source(file.path("local", "packages-to-build.R")) + save_rds_atomic(pkgs, "/mnt/cache/packages/pkgs_to_build.rds") + save_rds_atomic(pkgs[r_minor_sensitive == TRUE], "/mnt/cache/packages/r_minor_sensitive_pkgs.rds") + message("Package snapshot recomputed.") +} + pkgs <- if (sensitive_only) { readRDS("/mnt/cache/packages/r_minor_sensitive_pkgs.rds") } else { -- 2.54.0 From 0e484a8b371043fa7efb22d6a0ebaa7fea8a7452 Mon Sep 17 00:00:00 2001 From: pat-s Date: Thu, 18 Jun 2026 13:24:22 +0200 Subject: [PATCH 2/2] fix(ci): make build-all self-sufficient on agents without install-deps The primary build-all pass relied on build-all-versions-install-deps having populated the per-agent cache volume, but depends_on only orders the steps and does not co-locate them on one agent. A job landing on an agent where install-deps never ran used a stale bincraft that resolves `platform` to a zero-length value, breaking every metadata query ("Parameter 3 does not have length 1") and the system-dependency install ("argument is of length zero"). - Pin bincraft @v4.2.3 in the primary build step, mirroring the R-minor pass. - Align the R-minor pass and install-deps to @v4.2.3 so the whole pipeline uses one version (install-deps previously installed HEAD). - Export OS/OS_VERSION/ARCH as runtime env vars so build-all.R's already-built dedup query targets the real platform instead of "-". - Derive the unarchive codename via bincraft::set_codename(NULL) instead of the malformed paste(OS, OS_VERSION). --- .crow/build-all-versions-install-deps.yaml | 5 +++-- .crow/build-all-versions.yaml | 22 +++++++++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.crow/build-all-versions-install-deps.yaml b/.crow/build-all-versions-install-deps.yaml index ad51300..97610df 100644 --- a/.crow/build-all-versions-install-deps.yaml +++ b/.crow/build-all-versions-install-deps.yaml @@ -62,8 +62,9 @@ steps: # - rm -rf /mnt/cache/R-pkgs - mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages - git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git . - - git clone -q https://codefloe.com/rpkgs/bincraft.git /tmp/bincraft - - /opt/R/$R_VERSION/bin/R -q -e 'pak::sysreqs_db_update(); pak::local_install("/tmp/bincraft"); pak::pak(c("RPostgres", "s3fs", "data.table", "future", "jsonlite")); packageVersion("bincraft")' + # Pin the same bincraft version the build steps use, so the precomputed + # snapshot and the per-agent library stay consistent across the pipeline. + - /opt/R/$R_VERSION/bin/R -q -e 'pak::sysreqs_db_update(); pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.3"); pak::pak(c("RPostgres", "s3fs", "data.table", "future", "jsonlite")); packageVersion("bincraft")' - /opt/R/$R_VERSION/bin/R -q -e "source('local/packages-to-build.R'); saveRDS(pkgs, '/mnt/cache/packages/pkgs_to_build.rds'); saveRDS(pkgs[r_minor_sensitive == TRUE], '/mnt/cache/packages/r_minor_sensitive_pkgs.rds'); sprintf('Precomputed %s package versions (%s r-minor-sensitive)', nrow(pkgs), nrow(pkgs[r_minor_sensitive == TRUE]))" backend_options: docker: diff --git a/.crow/build-all-versions.yaml b/.crow/build-all-versions.yaml index 639ce80..77f5b77 100644 --- a/.crow/build-all-versions.yaml +++ b/.crow/build-all-versions.yaml @@ -90,6 +90,13 @@ steps: from_secret: GITHUB_PAT # normal env vars GIT_USER: pat-s + # Export the platform selectors as runtime env vars. They are otherwise + # only available for ${...} interpolation (image/volume), so build-all.R's + # `Sys.getenv("OS")/("OS_VERSION")/("ARCH")` would be empty and its + # already-built dedup query would match platform "-" and skip nothing. + OS: ${OS} + OS_VERSION: ${OS_VERSION} + ARCH: ${ARCH} # set the location of the 'pkgcache' cache dir which persists the R package dependencies needed to install the packages themselves R_PKG_CACHE_DIR: ${R_PKG_CACHE_DIR} R_LIBS_USER: /mnt/cache/R-pkgs @@ -100,6 +107,14 @@ steps: commands: - git clone -q https://pat-s:$$REPO_RO_TOKEN@git.devxy.io/devxy/build-cran-binaries.git . - mkdir -p /mnt/cache/pkgcache /mnt/cache/R-pkgs /mnt/cache/ccache /mnt/cache/packages + # The primary pass must not rely on build-all-versions-install-deps having + # run on *this* agent: depends_on only orders the steps, but the cache + # volume is per-agent, so a job landing on an agent where install-deps did + # not run would otherwise use a stale bincraft (which resolves `platform` + # to a zero-length value and breaks every metadata query and the sysdeps + # install). Pin bincraft here, exactly like the R-minor pass below. + - rm -rf /mnt/cache/R-pkgs/00LOCK-* + - /opt/R/$R_VERSION/bin/R -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.3") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.3")' - XVFB=$(command -v xwfb-run 2>/dev/null || command -v xvfb-run); XVFB_ARGS=""; if command -v xwfb-run >/dev/null 2>&1; then dnf install -y -q weston 2>/dev/null; XVFB_ARGS="-c weston"; fi - $XVFB $XVFB_ARGS -n $SPLIT_INDEX -- /opt/R/$R_VERSION/bin/Rscript local/build-all.R $SPLIT_INTO $SPLIT_INDEX $NCPUS 2>&1 - | @@ -111,11 +126,12 @@ steps: echo "=== R-minor-sensitive pass under R $RV ===" LIB="/mnt/cache/R-pkgs-$RMINOR" mkdir -p "$LIB" - R_LIBS_USER="$LIB" "$(dirname "$RBIN")/R" -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.2") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.2")' || true + R_LIBS_USER="$LIB" "$(dirname "$RBIN")/R" -q -e 'if (!requireNamespace("bincraft", quietly = TRUE) || packageVersion("bincraft") != "4.2.3") pak::pak("git::https://codefloe.com/rpkgs/bincraft.git@v4.2.3")' || true R_LIBS_USER="$LIB" $XVFB $XVFB_ARGS -n $SPLIT_INDEX -- "$(dirname "$RBIN")/Rscript" local/build-all.R --sensitive-only $SPLIT_INTO $SPLIT_INDEX $NCPUS 2>&1 || true done - # archive missed packages - - /opt/R/$R_VERSION/bin/R -q -e "bincraft::process_unarchived_pkgs(paste(Sys.getenv('OS'), Sys.getenv('OS_VERSION')), Sys.getenv('ARCH'), workers = $NCPUS)" + # archive missed packages; first arg is the codename (e.g. "alpine324"), + # derived via bincraft like the upload step, not paste(OS, OS_VERSION). + - /opt/R/$R_VERSION/bin/R -q -e "bincraft::process_unarchived_pkgs(bincraft::set_codename(NULL), Sys.getenv('ARCH'), workers = $NCPUS)" backend_options: docker: resources: -- 2.54.0