why future_promise error is "Unhandled" with onRejected

208 Views Asked by At

Using future_promise with catch(.) (or then(onRejected=)), the error is still marked as "Unhandled" even though I think I'm attempting to handle it.

library(future)
library(promises)
plan(multicore, workers = 3)

Sys.getpid()
# [1] 1270066
nbrOfFreeWorkers()
# [1] 3
thisproc <- promises::future_promise({
  setTimeLimit(elapsed = 2, transient = TRUE)
  Sys.sleep(3)
  1L
}, seed = TRUE) %>%
  promises::then(
    function(val) {
      message("survived: ", val)
      val
    }) %>%
  catch(
    function(error) {
      message("terminated: ", substring(conditionMessage(error), 1, 16))
      NULL
    })
# terminated: Unexpected resul
# Unhandled promise error: Unexpected result (of class ‘NULL’ != ‘FutureResult’) retrieved for MulticoreFuture future (label = ‘<none>’, expression = ‘{; setTimeLimit(elapsed = 2, transient \
# = TRUE); Sys.sleep(3); 1L; }’):

once that returned, then

nbrOfFreeWorkers()
# [1] 2
resetWorkers(plan())
# NULL
nbrOfFreeWorkers()
# [1] 3

(I used substring just to differentiate an error-like string messaged by my function, and the full condition message being catted to the console.)

  1. It reports "Unhandled" despite the code handling it (the terminated: is printed);
  2. It reports it twice;

and most importantly,

  1. The worker is not freed until I explicitly free it, despite the then-chain functioning.

According to the source, it appears that rejectionHandled is only referenced/set in this one file, and it should be setting the flag:

    doRejectFinalReason = function(reason) {
      private$value <- reason
      private$state <- "rejected"

      later::later(function() {
          lapply(private$onRejected, function(f) {
            private$rejectionHandled <- TRUE
            f(private$value)
          })
          private$onRejected <- list()

        later::later(~{
          if (!private$rejectionHandled) {
            # warning() was unreliable here
            cat(file=stderr(), "Unhandled promise error: ", reason$message, "\n", sep = "")
          }
        })
      })
    }

I assumed that since f(private$value) is called (as evidenced by the "terminated:" message I inserted), then the private_rejectionHandled should already have been updated. There are no other errors in this pipe, so it should not have reset the rejectionHandled flag.

Incidentally, I tried (without success) to call later::run_now() throughout the process to make sure that all promises are being run, though I was only stabbing in the dark (and it did not change the result).

Also, I can find attributes(thisproc)$promise_impl$.__enclos_env__$private$rejectionHandled, see it is FALSE, and change it to TRUE, but we still see the "Unhandled" console output, indicating something else is at work here. https://github.com/rstudio/promises/issues/86#issuecomment-1252420305 is related (or perhaps the same thing).


Linux, R-4.2.2, future-1.30.0 (1.31.0 is released), promises-1.2.0.1, later-1.3.0.

0

There are 0 best solutions below