futureverse / futureverse/future

Entire global environment getting passed along with user-defined (global) functions in shiny

Open
#833 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
R
Stars
1k
Forks
92
PR merge metrics
No merged PRs in 30d

Description

**Describe the bug**

When calling a global function in a future (_promise) the entire global environment is getting passed along with the user-defined function. This, in a shiny context, also includes the server and the ui function, which depending on the apps size results in a long processing time.

This might be a [regression](https://github.com/futureverse/future/issues/176) (or promises::future_promise()'s behaviour?).

**Reproduce example**

```
library(future)
library(shiny)
library(bslib)
library(promises)
library(future.mirai)

plan(future.mirai::mirai_multisession)

some_other_global_var <- 1L

# size: 21750
# global_function <- local(function(){
# # Slow operation
# Sys.sleep(2)
# sample(1:100, 1)
# })

# size: 418991
global_function <- function(){
# Slow operation
Sys.sleep(2)
sample(1:100, 1)
}

ui <- page_fluid(
titlePanel("Extended Task Demo"),
p(
'Click the button below to perform a "calculation"',
"that takes a while to perform."
),
input_task_button("recalculate", "Recalculate"),
p(textOutput("result"))
)

server <- function(input, output) {
rand_task <- ExtendedTask$new(function() {
print(environment(global_function))
print(ls(environment(global_function)))
print(future:::objectSize(global_function))
future_promise(
{
global_function()
}, seed = 1L
)
})

bind_task_button(rand_task, "recalculate")

observeEvent(input$recalculate, {
# Invoke the extended in an observer
rand_task$invoke()
})

output$result <- renderText({
number <- rand_task$result()
paste0("Your number is ", number, ".")
})
}

shinyApp(ui, server)
```

**Expected behavior**

Passing only the needed objects.

**Session information**

```r
R version 4.6.0 (2026-04-24 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 10 x64 (build 19045)

Matrix products: default
LAPACK version 3.12.1

locale:
[1] LC_COLLATE=German_Germany.utf8 LC_CTYPE=German_Germany.utf8 LC_MONETARY=German_Germany.utf8 LC_NUMERIC=C
[5] LC_TIME=German_Germany.utf8

time zone: Europe/Berlin
tzcode source: internal

attached base packages:
[1] stats graphics grDevices utils datasets methods base

other attached packages:
[1] future.mirai_1.0.0 promises_1.5.0 bslib_0.11.0 future_1.70.0 shiny_1.14.0

loaded via a namespace (and not attached):
[1] jsonlite_2.0.0 compiler_4.6.0 Rcpp_1.1.1-1.1 parallel_4.6.0 later_1.4.8 jquerylib_0.1.4 globals_0.19.1 fastmap_1.2.0
[9] mime_0.13 R6_2.6.1 nanonext_1.9.1 tibble_3.3.1 mirai_2.7.1 pillar_1.11.1 rlang_1.2.0 cachem_1.1.0
[17] httpuv_1.6.17 fs_2.1.0 sass_0.4.10 otel_0.2.0 memoise_2.0.1 cli_3.6.6 withr_3.0.3 magrittr_2.0.5
[25] digest_0.6.39 rstudioapi_0.19.0 fontawesome_0.5.3 xtable_1.8-8 lifecycle_1.0.5 vctrs_0.7.3 glue_1.8.1 listenv_1.0.0
[33] codetools_0.2-20 parallelly_1.47.0 pkgconfig_2.0.3 tools_4.6.0 htmltools_0.5.9

*** Package versions
future 1.70.0, parallelly 1.47.0, parallel 4.6.0, globals 0.19.1, listenv 1.0.0

*** Allocations
availableCores():
system /proc/self/status
4 4
availableWorkers():
$system
[1] "localhost" "localhost" "localhost" "localhost"

*** Settings
- future.plan=
- future.fork.multithreading.enable=
- future.globals.maxSize=
- future.globals.onReference=
- future.resolve.recursive=
- future.rng.onMisuse=
- future.wait.timeout=
- future.wait.interval=
- future.wait.alpha=
- future.startup.script=

*** Backends
Number of workers: 4
List of future strategies:
1. mirai_multisession:
- args: function (..., workers = availableCores(), envir = parent.frame())
- tweaked: FALSE
- call: plan(future.mirai::mirai_multisession)

*** Basic tests
Main R session details:
pid r sysname release version nodename machine login user effective_user
1 8372 4.6.0 Windows 10 x64 build 19045 host001 x86-64 user001 user001 user001

```

Contributor guide

Open the contributing guide

Research direction

Start by running the reproducible Shiny example with future.mirai::mirai_multisession and inspect the reported environment and object size for global_function. Compare the behavior of future_promise() with the referenced future issue and determine why the server and UI are included. Done means only the needed objects are passed and the unnecessary processing time is removed.

Written by the indexing model from the issue text.

Assessment

Tech stack
r
Domain
distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.