Cross-session / global reactive / reactivePoll

I was hoping to create a cross-session reactivePoll which provides all shiny sessions with the same (expensive) DB query result by setting it's session argument to NULL.

The example "Cross-session reactive file reader" given in ?reactiveFileReader mentions:

In this example, all sessions share the same reader, so read.csv only gets executed once no matter how many user sessions are connected.

reactiveFileReader is based on reactivePoll so I thought the behaviour should be the same when setting session = NULL.

However it seems reactivePoll's valueFunc still is executed for each session. Please see the following example:

library(shiny)

ui <- fluidPage(textOutput("time"))

server <- function(input, output, session) {
  currentTime <- reactivePoll(
    intervalMillis = 2000,
    session = NULL,
    checkFunc = function() {
      print(paste("checkFunc session:", session$token))
      as.numeric(Sys.time())
    },
    valueFunc = function() {
      print(paste(as.character(Sys.time()), "session:", session$token))
      as.character(Sys.time())
    }
  )
  output$time <- renderText(currentTime())
}

shinyApp(ui, server)

Animation

Accordingly my question is:

Is it somehow possible to create a session independent reactive which is executed once per specified interval and feeds all sessions?

Btw. I'm aware that we can define global reactiveValues each session can access as done here - but this approach would still fire my db-query for each session.

Here is a related SO post.

I found a workaround - here only one active session is allowed to update the global reactiveValues:

library(shiny)

ui <- fluidPage(textOutput("time"))

rv <- reactiveValues()

server <- function(input, output, session) {
  
  isolate(rv$active_sessions <- c(rv$active_sessions, session$token))
  
  observe({
    invalidateLater(2000)
    if(rv$active_sessions[1] == session$token){
      print(paste(as.character(Sys.time()), "session:", session$token))
      rv$current_time <- as.character(Sys.time())
    }
  })
  
  output$time <- renderText(rv$current_time)
  
  onSessionEnded(fun = function(){
    isolate(rv$active_sessions <- setdiff(rv$active_sessions, session$token))
  })
}

shinyApp(ui, server)

Animation

I'm still wondering if there is a cleaner way without relying on session$token

Hi there,

You can simply put the reactive poll outside the server function, and this will ensure the variable is shared across all sessions and only depends on the timer set. Note that in this scenario, you cannot use any reactive values inside the reactivePoll, as these are session-specific (including the session variable itself)

library(shiny)

ui <- fluidPage(textOutput("time"))

currentTime <- reactivePoll(
  intervalMillis = 3000,
  session = NULL,
  checkFunc = function() {
    as.numeric(Sys.time())
  },
  valueFunc = function() {
    as.character(Sys.time())
  }
)

server <- function(input, output, session) {
  output$time <- renderText(currentTime())
}

shinyApp(ui, server)

Hope this helps,
PJ

1 Like

Thanks! Now it seems obvious :see_no_evil:.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.