Skip to content

Commit 554a2ee

Browse files
Add conditionMessage() for FutureCondition. Include more metadata
1 parent 48a5161 commit 554a2ee

File tree

6 files changed

+159
-52
lines changed

6 files changed

+159
-52
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Package: future
2-
Version: 1.68.0-9001
2+
Version: 1.68.0-9002
33
Title: Unified Parallel and Distributed Processing in R for Everyone
44
Depends:
55
R (>= 3.2.0)

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ S3method(cancel,default)
1818
S3method(cancel,environment)
1919
S3method(cancel,list)
2020
S3method(cancel,listenv)
21+
S3method(conditionMessage,FutureCondition)
2122
S3method(futures,environment)
2223
S3method(futures,list)
2324
S3method(futures,listenv)

NEWS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Version (development version)
22

3+
## New Features
4+
5+
* Add `conditionMessage()` for `FutureCondition`, which appends
6+
meta-data information to the original message.
7+
8+
* Add more metadata to `FutureCondition` objects by default, e.g. in
9+
which session (including UUID, hostname, and PID) and when the
10+
condition was created.
11+
312
## Bug Fixes
413

514
* `plan(..., interrupts = ...)` would produce a warning on "Detected

R/backend_api-11.ClusterFutureBackend-class.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1518,7 +1518,7 @@ handleInterruptedFuture <- local({
15181518
} else {
15191519
event <- sprintf("was %s", state)
15201520
}
1521-
msg <- sprintf("Future (%s) of class %s %s, while running on %s", label, class(future)[1], event, sQuote(host))
1521+
msg <- sprintf("Future (%s) of class %s %s", label, class(future)[1], event)
15221522
if (inherits(node, "RichSOCKnode")) {
15231523
pid <- node[["session_info"]][["process"]][["pid"]]
15241524
if (!is.null(pid)) msg <- sprintf("%s (pid %s)", msg, pid)

R/protected_api-FutureCondition-class.R

Lines changed: 105 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@
88
#'
99
#' @param message A message condition.
1010
#'
11-
#' @param call The call stack that led up to the condition.
11+
#' @param call (optional) The call stack that led up to the condition.
1212
#'
13-
#' @param uuid A universally unique identifier for the future associated with
14-
#' this FutureCondition.
13+
#' @param by (optional) A session UUID object.
1514
#'
16-
#' @param future The [Future] involved.
15+
#' @param when (optional) A [POSIXct] timestamp for when the condition was
16+
#' created.
17+
#'
18+
#' @param label (optional) A future label.
19+
#'
20+
#' @param uuid (optional) A universally unique identifier for the future
21+
#' associated with this FutureCondition.
22+
#'
23+
#' @param future (optional) The [Future] involved.
1724
#'
1825
#' @return An object of class FutureCondition which inherits from class
1926
#' \link[base:conditions]{condition} and FutureMessage, FutureWarning,
@@ -24,7 +31,7 @@
2431
#'
2532
#' @export
2633
#' @keywords internal
27-
FutureCondition <- function(message, call = NULL, uuid = future[["uuid"]], future = NULL) {
34+
FutureCondition <- function(message, call = NULL, by = session_uuid(), when = NULL, uuid = future[["uuid"]], label = future[["label"]], future = NULL) {
2835
## Support different types of input
2936
if (inherits(message, "condition")) {
3037
cond <- message
@@ -57,46 +64,104 @@ FutureCondition <- function(message, call = NULL, uuid = future[["uuid"]], futur
5764
class <- c("FutureCondition", class)
5865
structure(list(message = message, call = call),
5966
class = class[!duplicated(class, fromLast = TRUE)],
60-
uuid = uuid, future = future)
67+
by = by, when = when,
68+
label = label, uuid = uuid, future = future)
6169
}
6270

6371

64-
#' @importFrom utils tail
72+
#' @importFrom utils tail capture.output
6573
#' @export
6674
print.FutureCondition <- function(x, ...) {
6775
NextMethod()
6876

77+
lines <- character(0L)
78+
79+
by <- attr(x, "by", exact = TRUE)
80+
when <- attr(x, "when", exact = TRUE)
81+
if (!is.null(by)) {
82+
source <- attr(by, "source", exact = TRUE)
83+
host <- source[["host"]]
84+
pid <- source[["pid"]]
85+
info <- c(host, sprintf("pid %d", pid), as.character(when))
86+
info <- paste(info, collapse = "; ")
87+
lines <- c(lines, sprintf("Occurred on: %s [%s]", by, info))
88+
} else if (!is.null(when)) {
89+
lines <- c(lines, sprintf("Occurred at: %s", when))
90+
}
91+
6992
uuid <- attr(x, "uuid", exact = TRUE)
70-
if (is.null(uuid)) {
71-
uuid <- "<NA>"
93+
label <- attr(x, "label", exact = TRUE)
94+
label <- if (is.null(label)) {
95+
sprintf("<%s>", paste(c("unnamed", tail(uuid, 1L)), collapse = "-"))
7296
} else {
73-
uuid <- paste(uuid, collapse = "-")
97+
label <- sQuote(label)
7498
}
75-
cat(sprintf("\n\nFuture UUID: %s\n", uuid))
99+
uuid <- if (is.null(uuid)) "<NA>" else paste(uuid, collapse = "-")
100+
lines <- c(lines, sprintf("Future: %s (%s)", uuid, label))
76101

77-
future <- attr(x, "future", exact = TRUE)
78102

103+
future <- attr(x, "future", exact = TRUE)
79104
if (!is.null(future)) {
80-
cat("\n\nDEBUG: BEGIN TROUBLESHOOTING HELP\n")
81-
82-
if (!is.null(future)) {
83-
cat("Future involved:\n")
84-
print(future)
85-
cat("\n")
86-
}
87-
88-
cat("DEBUG: END TROUBLESHOOTING HELP\n")
105+
lines <- c(lines, "", "DEBUG: BEGIN TROUBLESHOOTING HELP")
106+
lines <- c(lines, capture.output(print(future)))
107+
lines <- c(lines, "DEBUG: END TROUBLESHOOTING HELP")
89108
}
90109

110+
if (length(lines) > 0) {
111+
lines <- c("", lines)
112+
writeLines(lines)
113+
}
114+
91115
invisible(x)
92116
} ## print()
93117

94118

119+
#' @export
120+
conditionMessage.FutureCondition <- function(c) {
121+
msg <- NextMethod()
122+
123+
meta <- character()
124+
125+
uuid <- attr(c, "uuid", exact = TRUE)
126+
label <- attr(c, "label", exact = TRUE)
127+
label <- if (is.null(label)) {
128+
sprintf("<%s>", paste(c("unnamed", tail(uuid, 1L)), collapse = "-"))
129+
} else {
130+
label <- sQuote(label)
131+
}
132+
if (!is.null(uuid)) {
133+
uuid <- if (is.null(uuid)) "<NA>" else paste(uuid, collapse = "-")
134+
meta <- c(meta, sprintf("future %s (%s)", label, uuid))
135+
} else {
136+
meta <- c(meta, sprintf("future %s", label))
137+
}
138+
139+
when <- attr(c, "when", exact = TRUE)
140+
by <- attr(c, "by", exact = TRUE)
141+
if (!is.null(by)) {
142+
source <- attr(by, "source", exact = TRUE)
143+
host <- source[["host"]]
144+
pid <- source[["pid"]]
145+
info <- sprintf("on %s@%s<%d>", by, host, pid)
146+
if (!is.null(when)) info <- sprintf("%s at %s", info, when)
147+
meta <- c(meta, info)
148+
} else if (!is.null(when)) {
149+
meta <- c(meta, sprintf("at %s", when))
150+
}
151+
152+
if (length(meta) > 0) {
153+
meta <- paste(meta, collapse = "; ")
154+
msg <- sprintf("%s [%s]", msg, meta)
155+
}
156+
157+
msg
158+
}
159+
95160

96161
#' @rdname FutureCondition
97162
#' @export
98-
FutureMessage <- function(message, call = NULL, uuid = future[["uuid"]], future = NULL) {
99-
cond <- FutureCondition(message = message, call = call, uuid = uuid, future = future)
163+
FutureMessage <- function(message, call = NULL, ..., uuid = future[["uuid"]], future = NULL) {
164+
cond <- FutureCondition(message = message, call = call, ..., uuid = uuid, future = future)
100165
class <- c("FutureMessage", "message", class(cond))
101166
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
102167
cond
@@ -105,8 +170,8 @@ FutureMessage <- function(message, call = NULL, uuid = future[["uuid"]], future
105170

106171
#' @rdname FutureCondition
107172
#' @export
108-
FutureWarning <- function(message, call = NULL, uuid = future[["uuid"]], future = NULL) {
109-
cond <- FutureCondition(message = message, call = call, uuid = uuid, future = future)
173+
FutureWarning <- function(message, call = NULL, ..., uuid = future[["uuid"]], future = NULL) {
174+
cond <- FutureCondition(message = message, call = call, ..., uuid = uuid, future = future)
110175
class <- c("FutureWarning", "warning", class(cond))
111176
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
112177
cond
@@ -115,8 +180,8 @@ FutureWarning <- function(message, call = NULL, uuid = future[["uuid"]], future
115180

116181
#' @rdname FutureCondition
117182
#' @export
118-
FutureError <- function(message, call = NULL, uuid = future[["uuid"]], future = NULL) {
119-
cond <- FutureCondition(message = message, call = call, uuid = uuid, future = future)
183+
FutureError <- function(message, call = NULL, ..., uuid = future[["uuid"]], future = NULL) {
184+
cond <- FutureCondition(message = message, call = call, ..., uuid = uuid, future = future)
120185
class <- c("FutureError", "error", class(cond))
121186
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
122187
cond
@@ -125,12 +190,12 @@ FutureError <- function(message, call = NULL, uuid = future[["uuid"]], future =
125190

126191
#' @rdname FutureCondition
127192
#' @export
128-
RngFutureCondition <- function(message = NULL, call = NULL, uuid = future[["uuid"]], future = NULL) {
193+
RngFutureCondition <- function(message = NULL, call = NULL, ..., uuid = future[["uuid"]], future = NULL) {
129194
if (is.null(message)) {
130195
label <- sQuoteLabel(future)
131196
message <- sprintf("UNRELIABLE VALUE: Future (%s) unexpectedly generated random numbers without specifying argument 'seed'. There is a risk that those random numbers are not statistically sound and the overall results might be invalid. To fix this, specify 'seed=TRUE'. This ensures that proper, parallel-safe random numbers are produced. To disable this check, use 'seed=NULL', or set option 'future.rng.onMisuse' to \"ignore\".", label)
132197
}
133-
cond <- FutureCondition(message = message, call = call, uuid = uuid, future = future)
198+
cond <- FutureCondition(message = message, call = call, ..., uuid = uuid, future = future)
134199
class <- c("RngFutureCondition", class(cond))
135200
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
136201
cond
@@ -190,13 +255,13 @@ UnexpectedFutureResultError <- function(future, hint = NULL) {
190255

191256
#' @rdname FutureCondition
192257
#' @export
193-
GlobalEnvMisuseFutureCondition <- function(message = NULL, call = NULL, differences = NULL, uuid = future[["uuid"]], future = NULL) {
258+
GlobalEnvMisuseFutureCondition <- function(message = NULL, call = NULL, ..., differences = NULL, uuid = future[["uuid"]], future = NULL) {
194259
if (is.null(message)) {
195260
label <- sQuoteLabel(future)
196261
message <- sprintf("%s (%s) added variables to the global environment. A future expression should never assign variables to the global environment - neither by assign() nor by <<-: [n=%d] %s", class(future)[1], label, length(differences[["added"]]), commaq(differences[["added"]]))
197262
message <- sprintf("%s. See also help(\"future.options\", package = \"future\")", message)
198263
}
199-
cond <- FutureCondition(message = message, call = call, uuid = uuid, future = future)
264+
cond <- FutureCondition(message = message, call = call, ..., uuid = uuid, future = future)
200265
cond[["differences"]] <- differences
201266
class <- c("GlobalEnvMisuseFutureCondition", class(cond))
202267
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
@@ -224,7 +289,7 @@ GlobalEnvMisuseFutureError <- function(...) {
224289

225290
#' @rdname FutureCondition
226291
#' @export
227-
ConnectionMisuseFutureCondition <- function(message = NULL, call = NULL, differences = NULL, uuid = future[["uuid"]], future = NULL) {
292+
ConnectionMisuseFutureCondition <- function(message = NULL, call = NULL, ..., differences = NULL, uuid = future[["uuid"]], future = NULL) {
228293
if (is.null(message)) {
229294
label <- sQuoteLabel(future)
230295
message <- sprintf("%s (%s) added, removed, or modified connections. A future expression must close any opened connections and must not close connections it did not open", class(future)[1], label)
@@ -247,7 +312,7 @@ ConnectionMisuseFutureCondition <- function(message = NULL, call = NULL, differe
247312
}
248313
message <- sprintf("%s. See also help(\"future.options\", package = \"future\")", message)
249314
}
250-
cond <- FutureCondition(message = message, call = call, uuid = uuid, future = future)
315+
cond <- FutureCondition(message = message, call = call, ..., uuid = uuid, future = future)
251316
cond[["differences"]] <- differences
252317
class <- c("ConnectionMisuseFutureCondition", "MisuseFutureCondition", class(cond))
253318
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
@@ -276,7 +341,7 @@ ConnectionMisuseFutureError <- function(...) {
276341

277342
#' @rdname FutureCondition
278343
#' @export
279-
DeviceMisuseFutureCondition <- function(message = NULL, call = NULL, differences = NULL, uuid = future[["uuid"]], future = NULL) {
344+
DeviceMisuseFutureCondition <- function(message = NULL, call = NULL, ..., differences = NULL, uuid = future[["uuid"]], future = NULL) {
280345
if (is.null(message)) {
281346
label <- sQuoteLabel(future)
282347
message <- sprintf("%s (%s) added, removed, or modified devices. A future expression must close any opened devices and must not close devices it did not open", class(future)[1], label)
@@ -292,7 +357,7 @@ DeviceMisuseFutureCondition <- function(message = NULL, call = NULL, differences
292357
}
293358
message <- sprintf("%s. See also help(\"future.options\", package = \"future\")", message)
294359
}
295-
cond <- FutureCondition(message = message, call = call, uuid = uuid, future = future)
360+
cond <- FutureCondition(message = message, call = call, ..., uuid = uuid, future = future)
296361
cond[["differences"]] <- differences
297362
class <- c("DeviceMisuseFutureCondition", "MisuseFutureCondition", class(cond))
298363
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
@@ -321,7 +386,7 @@ DeviceMisuseFutureError <- function(...) {
321386

322387
#' @rdname FutureCondition
323388
#' @export
324-
DefaultDeviceMisuseFutureCondition <- function(message = NULL, incidents = NULL, call = NULL, uuid = future[["uuid"]], future = NULL) {
389+
DefaultDeviceMisuseFutureCondition <- function(message = NULL, call = NULL, ..., incidents = NULL, uuid = future[["uuid"]], future = NULL) {
325390
if (is.null(message)) {
326391
label <- sQuoteLabel(future)
327392
message <- sprintf("%s (%s) opened the default graphics device", class(future)[1], label)
@@ -340,7 +405,7 @@ DefaultDeviceMisuseFutureCondition <- function(message = NULL, incidents = NULL,
340405
message <- sprintf("%s. This happens for instance if plot() is called without explicitly opening a graphics device before. Using default graphics devices in parallel processing will typically leave behind an 'Rplots.pdf' file on the parallel worker. If the intention is to plot to file, please open a graphics device explicitly (e.g. pdf() or png()) [recommended], or set your preferred `options(default = ...)` [not recommended], then plot, and make sure to close it at the end (i.e. dev.off())", message)
341406
message <- sprintf("%s. See also help(\"future.options\", package = \"future\")", message)
342407
}
343-
cond <- FutureCondition(message = message, call = call, uuid = uuid, future = future)
408+
cond <- FutureCondition(message = message, call = call, ..., uuid = uuid, future = future)
344409
class <- c("DefaultDeviceMisuseFutureCondition", "MisuseFutureCondition", class(cond))
345410
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
346411
cond
@@ -377,8 +442,8 @@ FutureLaunchError <- function(..., future = NULL) {
377442

378443
#' @rdname FutureCondition
379444
#' @export
380-
FutureInterruptError <- function(..., future = NULL) {
381-
cond <- FutureError(..., future = future)
445+
FutureInterruptError <- function(..., when = Sys.time(), future = NULL) {
446+
cond <- FutureError(..., when = when, future = future)
382447
class <- c("FutureInterruptError", class(cond))
383448
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
384449
cond
@@ -387,7 +452,7 @@ FutureInterruptError <- function(..., future = NULL) {
387452
#' @rdname FutureCondition
388453
#' @export
389454
FutureCanceledError <- function(..., future = NULL) {
390-
cond <- FutureError(..., future = future)
455+
cond <- FutureInterruptError(..., future = future)
391456
class <- c("FutureCanceledError", class(cond))
392457
class(cond) <- class[!duplicated(class, fromLast = TRUE)]
393458
cond

0 commit comments

Comments
 (0)