Search code examples
rsessionshinyglobal-variables

How many users are connected to my Shiny application?


I work on a Shiny application with shinydashboard and somewhere in the app I want to show a notification telling the user how many other users are connected to the application at the same time.

I came up with a first piece of code that seems to work:

library(shiny)
ui=fluidPage(uiOutput("text"))
number.users <- 0 # global variable
server= function(input, output, session){
     already.counted = FALSE
     autoInvalidate = reactiveTimer(2000)
     observe({
          if (!already.counted) {
               already.counted <- TRUE
               number.users <<- number.users + 1
          }
     })
     output$text = renderUI({
          autoInvalidate()
          h1(paste0("There are ", number.users, " user(s) connected to this app"))
          })
     onSessionEnded(function(){number.users <<- number.users - 1})
}

However it's not very "clean" and I'm afraid that my call to observe and the invalidate every 2 secs are adding some useless computing time to my (already heavy) app. I was wondering if there was some kind of function in shiny that triggers an event at the start of each new session, something like onsessionstart() that I could use directly to increment the global variable number.users, and a way to notify other sessions that a new session has been opened? Or is there any simpler way to go?

Thanks


Solution

  • The root server function is called once for every new session, and effectively serves as the "onSessionStart" callback. I think what you're doing is fine, except the observe isn't really necessary.

    To share global state between sessions in a more reactive manner, you can initialize a reactiveVal or reactiveValues object in global scope (outside of a reactive context), and then take a reactive dependency on it within each session. Any updates to these reactive values will immediately propagate to all other sessions.

    library(shiny)
    
    users = reactiveValues(count = 0)
    
    ui = fluidPage(uiOutput("text"))
    
    server = function(input, output, session) {
      onSessionStart = isolate({
        users$count = users$count + 1
      })
    
      onSessionEnded(function() {
        isolate({
          users$count = users$count - 1
        })
      })
    
      output$text = renderUI({
        h1(paste0("There are ", users$count, " user(s) connected to this app"))
      })
    }
    
    shinyApp(ui, server)
    

    Btw, a more complex example of inter-session communication, though maybe a bit old now, is the Shiny chat room app - http://shiny.rstudio.com/gallery/chat-room.html