Skip to content

Commit 6125208

Browse files
Merge branch 'release/1.68.0'
2 parents 793d2e4 + 3f33765 commit 6125208

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1417
-2453
lines changed

.github/workflows/R-CMD-check.yaml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,12 @@ jobs:
7676
r-version: ${{ matrix.config.r }}
7777
http-user-agent: ${{ matrix.config.http-user-agent }}
7878
use-public-rspm: true
79-
79+
80+
- name: Install system dependencies for Rmpi (OpenMPI)
81+
if: runner.os == 'Linux'
82+
run: |
83+
sudo apt install -y libopenmpi-dev openmpi-bin
84+
8085
- uses: r-lib/actions/setup-r-dependencies@v2
8186
with:
8287
extra-packages: |
@@ -124,7 +129,7 @@ jobs:
124129
R_FUTURE_PSOCK_RELAY_IMMEDIATE: ${{ matrix.config.psock_relay_immediate }}
125130
run: |
126131
if ("${{ matrix.config.strict }}" == "true") {
127-
Sys.setenv(R_FUTURE_CONNECTIONS_ONMISUSE = "error[details=TRUE]")
132+
# FIXME: Sys.setenv(R_FUTURE_CONNECTIONS_ONMISUSE = "error[details=TRUE]")
128133
Sys.setenv(R_FUTURE_GLOBALENV_ONMISUSE = "error")
129134
Sys.setenv(R_FUTURE_RNG_ONMISUSE = "error")
130135
}
@@ -140,7 +145,7 @@ jobs:
140145
if: runner.os == 'Windows'
141146
run: |
142147
if ("${{ matrix.config.strict }}" == "true") {
143-
Sys.setenv(R_FUTURE_CONNECTIONS_ONMISUSE = "error[details=TRUE]")
148+
# FIXME: Sys.setenv(R_FUTURE_CONNECTIONS_ONMISUSE = "error[details=TRUE]")
144149
Sys.setenv(R_FUTURE_DEVICES_ONMISUSE = "error")
145150
Sys.setenv(R_FUTURE_GLOBALENV_ONMISUSE = "error")
146151
Sys.setenv(R_FUTURE_RNG_ONMISUSE = "error")
@@ -152,6 +157,16 @@ jobs:
152157
)
153158
shell: Rscript {0}
154159

160+
- name: Check MPI clusters (not macOS)
161+
if: runner.os != 'macOS'
162+
env:
163+
NOT_CRAN: true
164+
OMPI_MCA_rmaps_base_oversubscribe: 1
165+
run: |
166+
install.packages(c("Rmpi", "snow"))
167+
future:::testme("mpi")
168+
shell: Rscript {0}
169+
155170
- name: Upload check results
156171
if: failure()
157172
uses: actions/upload-artifact@v4

.github/workflows/revdepcheck-top.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- { r: "release", pkg: "future.apply" }
2424
- { r: "release", pkg: "furrr", not_cran: false }
2525
- { r: "release", pkg: "future.tests" }
26-
- { r: "release", pkg: "promises" }
26+
- { r: "release", pkg: "promises" , force_suggests: false }
2727
- { r: "release", pkg: "shiny", not_cran: false }
2828
- { r: "release", pkg: "plumber" }
2929
- { r: "release", pkg: "future.batchtools" , globals: develop, label: 'globals develop' }
@@ -96,6 +96,10 @@ jobs:
9696
export NOT_CRAN=false
9797
fi
9898
echo "NOT_CRAN=${NOT_CRAN:-<not set>}"
99+
if [[ "${{ matrix.config.force_suggests }}" == "false" ]]; then
100+
export _R_CHECK_FORCE_SUGGESTS_=false
101+
fi
102+
echo "_R_CHECK_FORCE_SUGGESTS_=${_R_CHECK_FORCE_SUGGESTS_:-<not set>}"
99103
R CMD check --no-manual --as-cran "$(basename "$url")"
100104
101105
- name: Upload check results

.github/workflows/tmate.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ jobs:
8585
http-user-agent: ${{ matrix.config.http-user-agent }}
8686
use-public-rspm: true
8787

88+
- name: Install system dependencies for Rmpi (OpenMPI)
89+
if: runner.os == 'Linux'
90+
run: |
91+
sudo apt install -y libopenmpi-dev openmpi-bin
92+
8893
- uses: r-lib/actions/setup-r-dependencies@v2
8994
with:
9095
extra-packages: |

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ revdep/data.sqlite
2323
revdep/checks/*
2424
revdep/library/*
2525
.Rdump
26+
.local/gh

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Package: future
2-
Version: 1.67.0
2+
Version: 1.68.0
33
Title: Unified Parallel and Distributed Processing in R for Everyone
44
Depends:
55
R (>= 3.2.0)
@@ -43,7 +43,7 @@ URL: https://future.futureverse.org, https://github.com/futureverse/future
4343
BugReports: https://github.com/futureverse/future/issues
4444
Language: en-US
4545
Encoding: UTF-8
46-
RoxygenNote: 7.3.2
46+
RoxygenNote: 7.3.3
4747
Roxygen: list(markdown = TRUE)
4848
Collate:
4949
'000.bquote.R'

NEWS.md

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,50 @@
1+
# Version 1.68.0 [2025-11-16]
2+
3+
This is the fifth rollout out of several towards a near-future major
4+
release. This has been made possible due to a multi-year effort of
5+
internal re-designs, work with package maintainers, release, and
6+
repeat. This release fixes a few more regressions introduced in
7+
**future** 1.40.0 (2025-04-10) and 1.67.0 (2025-07-29).
8+
9+
## Beta Features
10+
11+
* Calling `clusterEvalQ()` on a FutureCluster, introduced in
12+
**future** 1.58.0 (2025-06-05), is now an error by default - it
13+
used to be just a warning.
14+
15+
## Bug Fixes
16+
17+
* `result()` on a canceled and interrupted cluster future returned
18+
the future instead of producing a FutureInterruptError.
19+
20+
* The `cluster` backend failed when used with an `MPIcluster` as
21+
created by `parallel::makeCluster(..., type = "MPI")`. This bug was
22+
introduced in **future** (>= 1.40.0) [2025-04-10].
23+
24+
* Setting `R_FUTURE_PLAN=multisession` in an Renviron file, or a
25+
shell startup script, would result in a "fork bomb" when loading
26+
the **future** package. This happened because the setup of the
27+
future backend happened eagerly when the **future** package was
28+
loaded instead of being deferred to when the first future launched.
29+
This resulted in new, nested R workers being created recursively,
30+
until the machine ran out of resources. This bug was introduced in
31+
**future** (>= 1.67.0) [2025-07-29].
32+
33+
* ``value(..., reduce = structure(`+`, init = 42))`` is not
34+
supported, because `` `+` `` is a primitive function and one must
35+
not set attributes on primitive functions. `value()` detects this
36+
and produces an error suggestion to use `reduce = structure("+",
37+
init = 42)` instead. The latter still gave the same error, which is
38+
now fixed.
39+
40+
141
# Version 1.67.0 [2025-07-29]
242

343
This is the fourth rollout out of several towards a near-future major
444
release. This has been made possible due to a multi-year effort of
545
internal re-designs, work with package maintainers, release, and
6-
repeat. This release fixes a few more regressions introduced in future
7-
1.40.0 (2025-04-10).
46+
repeat. This release fixes a few more regressions introduced in
47+
**future** 1.40.0 (2025-04-10).
848

949
## Significant Changes
1050

@@ -57,9 +97,9 @@ repeat. This release fixes a few more regressions introduced in future
5797
This is the third rollout out of several towards a near-future major
5898
release that I am really excited about. This has been made possible
5999
due to a multi-year effort of internal re-designs, work with package
60-
maintainers, release, and repeat. This release fixes a few
61-
regressions introduced in future 1.40.0 (2025-04-10), despite passing
62-
[all unit, regression, and system
100+
maintainers, release, and repeat. This release fixes a few regressions
101+
introduced in **future** 1.40.0 (2025-04-10), despite passing [all
102+
unit, regression, and system
63103
tests](https://www.futureverse.org/quality.html).
64104

65105
## New Features
@@ -133,8 +173,8 @@ tests](https://www.futureverse.org/quality.html).
133173
This is the second rollout out of three-four major updates, which is
134174
now possible due to a multi-year effort of internal re-designs, work
135175
with package maintainers, release, and repeat. This release fixes two
136-
regressions introduced in future 1.40.0 (2025-04-10), despite passing
137-
[all unit, regression, and system
176+
regressions introduced in **future** 1.40.0 (2025-04-10), despite
177+
passing [all unit, regression, and system
138178
tests](https://www.futureverse.org/quality.html) of the Future API
139179
that we have built up over the years. On the upside, fixing these
140180
issues led to a greatly improved static-code analyzer for

R/backend_api-01-FutureBackend-class.R

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -253,33 +253,34 @@ makeFutureBackend <- function(evaluator, ..., debug = FALSE) {
253253
## Apply future plan tweaks
254254
args <- attr(evaluator, "tweaks")
255255
if (is.null(args)) args <- list()
256-
257256
if (debug) {
258257
mdebugf("Evaluator tweak arguments: [n=%d]", length(args))
259258
mstr(args)
260259
}
261260

262261
args2 <- formals(evaluator)
263-
args2[["..."]] <- NULL
264-
args2$lazy <- NULL ## bc multisession; should be removed
265-
names2 <- names(args2)
266-
if ("envir" %in% names2) {
267-
args2[["envir"]] <- NULL
268-
names2 <- names(args2)
269-
}
262+
## Drop never-used arguments
263+
args2$`...` <- NULL
264+
args2$envir <- NULL # legacy
265+
args2$lazy <- NULL # bc multisession; should be removed
270266
if (debug) {
271267
mdebugf("Evaluator formal arguments: [n=%d]", length(args2))
272-
mstr(args)
273-
}
274-
for (name in names2) {
275-
args[[name]] <- args2[[name]]
268+
mstr(args2)
276269
}
277270

271+
## Merge tweaked arguments and future-backend evaluator arguments
272+
for (name in names(args2)) args[[name]] <- args2[[name]]
278273
if (debug) {
279-
mdebugf("Backend factory arguments: [n=%d]", length(args2))
280-
mstr(args2)
274+
mdebugf("Arguments passed to the future-backend factory: [n=%d]", length(args))
275+
mstr(args)
281276
}
282-
backend <- do.call(factory, args = args, envir = environment(factory))
277+
278+
## Make tweaked arguments and future-backend evaluator arguments
279+
## available when calling the factory function
280+
envir <- new.env(parent = environment(factory))
281+
for (name in names(args)) envir[[name]] <- args[[name]]
282+
283+
backend <- do.call(factory, args = args, envir = envir)
283284
if (debug) mdebugf("Backend: <%s>", commaq(class(backend)))
284285
stop_if_not(inherits(backend, "FutureBackend"))
285286

R/backend_api-11.ClusterFutureBackend-class.R

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ launchFuture.ClusterFutureBackend <- function(backend, future, ...) {
234234

235235
## Does the cluster node communicate with a connection?
236236
## (if not, it's likely via MPI)
237-
stop_if_not(inherits(node, c("SOCK0node", "SOCKnode")))
238237
con <- node[["con"]]
239238
future[["nodeHasConnection"]] <- !is.null(con)
240239

@@ -776,7 +775,11 @@ result.ClusterFuture <- function(future, ...) {
776775
## worker also shutting done? If so, turn the error into a run-time
777776
## FutureInterruptError and revive the worker
778777
future <- handleInterruptedFuture(backend, future = future)
779-
return(future)
778+
stop_if_not(inherits(future, "Future"))
779+
result <- future[["result"]]
780+
if (inherits(result, "FutureError")) stop(result)
781+
stop_if_not(inherits(future, "FutureResult"))
782+
return(result)
780783
}
781784
assertValidConnection(future)
782785
}
@@ -1469,7 +1472,7 @@ getFutureBackendConfigs.ClusterFuture <- function(future, ..., debug = isTRUE(ge
14691472

14701473
## Does the cluster node communicate with a connection?
14711474
## (if not, it's via MPI)
1472-
if (!future[["nodeHasConnection"]]) return(list())
1475+
if (!isTRUE(future[["nodeHasConnection"]])) return(list())
14731476

14741477
capture <- list(
14751478
immediateConditionHandlers = list(

R/backend_api-11.SequentialFutureBackend-class.R

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,7 @@ getFutureBackendConfigs.UniprocessFuture <- function(future, ...) {
182182
#' @aliases uniprocess
183183
#' @export
184184
sequential <- function(..., envir = parent.frame()) {
185-
## WORKAROUNDS:
186-
## (1) fiery calls sequential() directly
187-
## https://github.com/thomasp85/fiery/issues/53
188-
if (!"fiery" %in% loadedNamespaces()) {
189-
stop("The future::sequential() function must never be called directly")
190-
}
191-
192-
f <- Future(..., envir = envir)
193-
class(f) <- c("SequentialFuture", "UniprocessFuture", "Future")
194-
f
185+
stop("The future::sequential() function must never be called directly")
195186
}
196187
class(sequential) <- c("sequential", "uniprocess", "future", "function")
197188
attr(sequential, "init") <- TRUE

R/backend_api-Future-class.R

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,9 @@ result <- function(future, ...) {
642642
#' @param \ldots Not used.
643643
#'
644644
#' @return The [FutureResult] object.
645+
#' It may signal a [FutureError], if there is a significant orchestration
646+
#' error. For example, if the parallel worker process terminated abruptly
647+
#' ("crashed"), then a [FutureInterruptError] is signaled.
645648
#'
646649
#' @details
647650
#' This function is only part of the _backend_ Future API.
@@ -1024,7 +1027,7 @@ getExpression.Future <- local({
10241027
#' @export
10251028
`$<-.Future` <- function(x, name, value) {
10261029
if (name == "state") {
1027-
if (!is.element(value, c("created", "running", "finished", "failed", "canceled", "interrupted"))) {
1030+
if (!is.element(value, c("created", "submitted", "running", "finished", "failed", "canceled", "interrupted"))) {
10281031
action <- getOption("future.state.onInvalid", "warning")
10291032

10301033
if (action != "ignore") {

0 commit comments

Comments
 (0)