Skip to content

Commit a77e229

Browse files
Merge branch 'release/0.10.1'
2 parents 88f9b32 + a7a9029 commit a77e229

File tree

7 files changed

+111
-50
lines changed

7 files changed

+111
-50
lines changed

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ jobs:
1919
- {os: windows-latest, r: 'devel' }
2020
- {os: windows-latest, r: 'release' }
2121
- {os: windows-latest, r: 'oldrel' }
22-
# - {os: macOS-latest, r: 'devel' }
22+
- {os: macOS-latest, r: 'devel' }
2323
- {os: macOS-latest, r: 'release' }
24-
# - {os: macOS-latest, r: 'oldrel' }
25-
# - {os: ubuntu-latest, r: 'devel' }
24+
- {os: macOS-latest, r: 'oldrel' }
25+
- {os: ubuntu-latest, r: 'devel' }
2626
- {os: ubuntu-latest, r: 'release' }
2727
- {os: ubuntu-latest, r: 'oldrel' }
2828
- {os: ubuntu-latest, r: 'oldrel-1' }
@@ -34,6 +34,7 @@ jobs:
3434
- {os: ubuntu-latest, r: 'release' , language: ko, label: ko }
3535
- {os: ubuntu-latest, r: 'release' , language: zh_CN, label: zh_CN }
3636
- {os: ubuntu-latest, r: 'release' , language: zh_TW, label: zh_TW }
37+
- {os: windows-latest, r: 'devel', future_version: develop, label: 'w/ future-develop' }
3738

3839
env:
3940
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
@@ -53,6 +54,7 @@ jobs:
5354
## Specific to futures
5455
R_PARALLELLY_AVAILABLECORES_SYSTEM: ${{ matrix.config.availablecores }}
5556
R_FUTURE_RNG_ONMISUSE: error
57+
R_FUTURE_VERSION: ${{ matrix.config.future_version }}
5658

5759
steps:
5860
- uses: actions/checkout@v4
@@ -77,6 +79,15 @@ jobs:
7779
install.packages(".", repos = NULL, type = "source") ## needed by parallel workers
7880
shell: Rscript {0}
7981

82+
- name: Test with specific future version?
83+
run: |
84+
future_version <- Sys.getenv("R_FUTURE_VERSION")
85+
if (nzchar(future_version)) {
86+
install.packages("remotes")
87+
remotes::install_github("futureverse/future", ref=future_version)
88+
}
89+
shell: Rscript {0}
90+
8091
- name: Session info
8192
run: |
8293
options(width = 100)

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Package: future.mirai
2-
Version: 0.10.0
2+
Version: 0.10.1
33
Depends:
44
future (>= 1.49.0)
55
Imports:

NEWS.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
# Version 0.10.1
2+
3+
## Bug Fix
4+
5+
* If a mirai future that was terminated abruptly (e.g. via
6+
`tools::pskill()` or by the operating system), then it was not
7+
detected as such. Instead it resulted in an unexpected error that
8+
could not be recovered from. Now it is detected and a
9+
`FutureInterruptError` is signaled, which can then be handled and
10+
the future may be `reset()`.
11+
12+
* `result()` on an interrupted mirai future would only throw
13+
FutureInterruptError the first time. Succeeding calls would result
14+
in other errors.
15+
16+
* `resolved()` on a mirai future already known to be interrupted
17+
would requery the mirai object, instead of returning TRUE
18+
immediately.
19+
20+
121
# Version 0.10.0
222

323
## New Features

R/MiraiFutureBackend-class.R

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ launchFuture.MiraiFutureBackend <- local({
9292
reg <- backend[["reg"]]
9393
FutureRegistry(reg, action = "add", future = future, earlySignal = FALSE)
9494

95+
stopifnot(inherits(future[["mirai"]], "mirai"))
96+
9597
invisible(future)
9698
}
9799
})
@@ -238,24 +240,27 @@ resolved.MiraiFuture <- function(x, ...) {
238240

239241
resolved <- NextMethod()
240242
if(resolved) {
241-
if (debug) mdebug("already resolved", debug = debug)
243+
if (debug) mdebug("already resolved")
242244
return(TRUE)
243245
}
244246

245-
if(x[["state"]] == "finished") {
246-
if (debug) mdebug("already resolved (state == finished)", debug = debug)
247+
if(x[["state"]] %in% c("finished", "interrupted")) {
248+
if (debug) mdebugf("already resolved (state == %s)", sQuote(x[["state"]]))
249+
stopifnot(inherits(x[["mirai"]], "mirai"))
247250
return(TRUE)
248251
} else if(x[["state"]] == "created") { # Not yet submitted to queue (iff lazy)
249252
if (debug) mdebug("just created; launching")
250253
x <- run(x)
254+
stopifnot(inherits(x[["mirai"]], "mirai"))
251255
return(FALSE)
252256
}
253257

254258
if (debug) mdebug_push("mirai::unresolved() ...")
255259
mirai <- x[["mirai"]]
260+
stopifnot(inherits(mirai, "mirai"))
256261
res <- unresolved(mirai)
257262
if (debug) {
258-
mstr(res, debug = debug)
263+
mstr(res)
259264
mdebug_pop()
260265
}
261266

@@ -266,16 +271,21 @@ resolved.MiraiFuture <- function(x, ...) {
266271
#' @importFrom future result FutureInterruptError
267272
#' @export
268273
result.MiraiFuture <- function(future, ...) {
269-
if(isTRUE(future[["state"]] == "finished")) {
270-
return(future[["result"]])
271-
}
272-
273274
debug <- isTRUE(getOption("future.mirai.debug"))
274275
if (debug) {
275276
mdebugf_push("result() for %s ...", class(future)[1])
277+
mdebugf("Future state: %s", sQuote(future[["state"]]))
276278
on.exit(mdebug_pop())
277279
}
278280

281+
282+
state <- future[["state"]]
283+
if (state == "finished") {
284+
return(future[["result"]])
285+
} else if (state == "interrupted") {
286+
stop(future[["result"]])
287+
}
288+
279289
backend <- future[["backend"]]
280290
reg <- backend[["reg"]]
281291

@@ -286,22 +296,34 @@ result.MiraiFuture <- function(future, ...) {
286296
dt <- dt[dt > 0]
287297
dt_str <- paste(sprintf("%s=%gs", names(dt), dt), collapse = ", ")
288298
mdebugf("collected mirai in %s", dt_str)
299+
mdebugf("mirai result class: %s", class(result)[1])
289300
}
290301

291302
if (inherits(result, "errorValue")) {
292-
label <- sQuoteLabel(future[["label"]])
303+
if (debug) mdebugf("mirai error value: %s", result)
304+
305+
label <- sQuoteLabel(future)
293306

294-
if (result == 20L) {
295-
state <- future[["state"]]
307+
if (result %in% c(19L, 20L)) {
296308
stop_if_not(state %in% c("canceled", "interrupted", "running"))
297-
298-
event <- if (state %in% "running") {
299-
event <- sprintf("failed for unknown reason while %s", state)
300-
future[["state"]] <- "interrupted"
301-
} else {
302-
event <- sprintf("was %s", state)
309+
310+
if (result == 19L) {
311+
## "If a daemon crashes or terminates unexpectedly during evaluation,
312+
## an 'errorValue' 19 (Connection reset) is returned."
313+
## Source: help("collect_mirai", package = "mirai")
314+
event <- sprintf("was terminated while %s", state)
315+
} else if (result == 20L) {
316+
## "Stops a 'mirai' if still in progress, causing it to resolve
317+
## immediately to an 'errorValue' 20 (Operation canceled)."
318+
## Source: help("stop_mirai", package = "mirai")
319+
event <- if (state %in% "running") {
320+
event <- sprintf("failed for unknown reason while %s", state)
321+
} else {
322+
event <- sprintf("was %s", state)
323+
}
303324
}
304325

326+
future[["state"]] <- "interrupted"
305327
msg <- sprintf("Future (%s) of class %s %s, while running on localhost (error code %d)", label, class(future)[1], event, result)
306328
if (debug) mdebug(msg)
307329
result <- FutureInterruptError(msg, future = future)
@@ -353,6 +375,7 @@ mirai_version <- local({
353375
#' @importFrom mirai call_mirai
354376
mirai_collect_future <- function(future) {
355377
mirai <- future[["mirai"]]
378+
stopifnot(inherits(mirai, "mirai"))
356379
call_mirai(mirai)$data
357380
}
358381

@@ -362,6 +385,7 @@ mirai_collect_future <- function(future) {
362385
#' @export
363386
interruptFuture.MiraiFutureBackend <- function(backend, future, ...) {
364387
mirai <- future[["mirai"]]
388+
stopifnot(inherits(mirai, "mirai"))
365389
stop_mirai(mirai)
366390
future[["state"]] <- "interrupted"
367391
future

R/utils-debug.R

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,63 +16,58 @@ debug_indent <- local({
1616
if (!exists(".debug", inherits = FALSE)) .debug <- new.env(parent = emptyenv())
1717
if (!"stack" %in% names(".debug")) .debug$stack <- list()
1818

19-
mdebug_push <- function(..., debug = isTRUE(getOption("future.debug"))) {
20-
if (!debug) return()
21-
msg <- mdebug(..., debug = debug)
19+
mdebug_push <- function(...) {
20+
msg <- mdebug(...)
2221
.debug$stack <- c(.debug$stack, msg)
2322
invisible(msg)
2423
}
2524

26-
mdebugf_push <- function(..., debug = isTRUE(getOption("future.debug"))) {
27-
if (!debug) return()
28-
msg <- mdebugf(..., debug = debug)
25+
mdebugf_push <- function(...) {
26+
msg <- mdebugf(...)
2927
.debug$stack <- c(.debug$stack, msg)
3028
invisible(msg)
3129
}
3230

33-
mdebug_pop <- function(..., debug = isTRUE(getOption("future.debug"))) {
34-
if (!debug) return()
31+
mdebug_pop <- function(...) {
3532
n <- length(.debug$stack)
36-
msg <- .debug$stack[n]
33+
msg <- c(...)
34+
if (length(msg) == 0) {
35+
msg <- .debug$stack[n]
36+
msg <- sprintf("%s done", msg)
37+
}
3738
.debug$stack <- .debug$stack[-n]
38-
mdebug(sprintf("%s done", msg), debug = debug)
39+
if (length(msg) == 0 || !is.na(msg)) mdebug(msg)
3940
}
4041

41-
mdebugf_pop <- function(..., debug = isTRUE(getOption("future.debug"))) {
42-
if (!debug) return()
42+
mdebugf_pop <- function(...) {
4343
n <- length(.debug$stack)
4444
msg <- .debug$stack[n]
4545
.debug$stack <- .debug$stack[-n]
46-
mdebug(sprintf("%s done", msg), debug = debug)
46+
mdebug(sprintf("%s done", msg))
4747
}
4848

49-
mdebug <- function(..., prefix = now(), debug = isTRUE(getOption("future.debug"))) {
50-
if (!debug) return()
49+
mdebug <- function(..., prefix = now()) {
5150
prefix <- paste(prefix, debug_indent(), sep = "")
5251
msg <- paste(..., sep = "")
5352
message(sprintf("%s%s", prefix, msg))
5453
invisible(msg)
5554
}
5655

57-
mdebugf <- function(..., appendLF = TRUE,
58-
prefix = now(), debug = isTRUE(getOption("future.debug"))) {
59-
if (!debug) return()
56+
mdebugf <- function(..., appendLF = TRUE, prefix = now()) {
6057
prefix <- paste(prefix, debug_indent(), sep = "")
6158
msg <- sprintf(...)
6259
message(sprintf("%s%s", prefix, msg), appendLF = appendLF)
6360
invisible(msg)
6461
}
6562

6663
#' @importFrom utils capture.output
67-
mprint <- function(..., appendLF = TRUE, prefix = now(), debug = isTRUE(getOption("future.debug"))) {
68-
if (!debug) return()
64+
mprint <- function(..., appendLF = TRUE, prefix = now()) {
6965
prefix <- paste(prefix, debug_indent(), sep = "")
7066
message(paste(prefix, capture.output(print(...)), sep = "", collapse = "\n"), appendLF = appendLF)
7167
}
7268

7369
#' @importFrom utils capture.output str
74-
mstr <- function(..., appendLF = TRUE, prefix = now(), debug = isTRUE(getOption("future.debug"))) {
75-
if (!debug) return()
70+
mstr <- function(..., appendLF = TRUE, prefix = now()) {
7671
prefix <- paste(prefix, debug_indent(), sep = "")
7772
message(paste(prefix, capture.output(str(...)), sep = "", collapse = "\n"), appendLF = appendLF)
7873
}

R/zzz.R

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,21 @@ with_assert <- function(expr, ...) { invisible(expr) }
2121
}
2222

2323
## Set 'debug' option by environment variable
24-
value <- Sys.getenv("R_FUTURE_MIRAI_DEBUG", "FALSE")
25-
value <- isTRUE(suppressWarnings(as.logical(value)))
26-
options(future.mirai.debug = value)
24+
value <- getOption("future.mirai.debug")
25+
if (is.null(value)) {
26+
value <- Sys.getenv("R_FUTURE_MIRAI_DEBUG", NA_character_)
27+
if (!is.na(value)) {
28+
value <- isTRUE(suppressWarnings(as.logical(value)))
29+
options(future.mirai.debug = value)
30+
}
31+
}
2732

2833
## Set 'queue' option by environment variable
29-
value <- Sys.getenv("R_FUTURE_MIRAI_QUEUE", NA_character_)
30-
if (!is.na(value)) {
31-
options(future.mirai.queue = value)
34+
value <- getOption("future.mirai.queue")
35+
if (is.null(value)) {
36+
value <- Sys.getenv("R_FUTURE_MIRAI_QUEUE", NA_character_)
37+
if (!is.na(value)) {
38+
options(future.mirai.queue = value)
39+
}
3240
}
3341
}

man/mirai_multisession.Rd

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)