Creating a reactiveFileReader directly within renderText

Are the two chunks of code

logTimer <- reactiveFileReader(intervalMillis = 500, session=NULL, 
                         filePath = logFile, readFunc = readLines)

output$logf <- renderPrint({
    logTimer()
})

and

 output$logf <- renderPrint({
      reactiveFileReader(intervalMillis = 500,  session=NULL,
                  filePath = logFile, readFunc = readLines)() 
    })

Equivalent in shiny ?

they are not perfectly equivalent if only for the reason that one creates an object named logTimer and the other doesnt.

Of course, but I wonder if creating the reactiveFileReader directly inside renderPrint is erroneous. Here is a (somewhat lengthy) chunk of code where it does not work whereas using a reactive variable does.

library(shiny)

library(processx)

asyncUI <- function(id) {
  ns <- NS(id)
  tagList(
    fluidRow(
      actionButton(ns("runProc"), "Sleep"),
      verbatimTextOutput(ns("logf")),
    ),
  )
}

asyncServer <- function(id, logFile)
  moduleServer(id, function(input, output, session) {

        mainProcess <<- NULL
    
    observeEvent(input$runProc, {
      mainProcess <<- process$new("count.tcsh")
    })
    procTimer <- reactivePoll(1000,  NULL, 
                              checkFunc = function() {
                                if(is.null(mainProcess))
                                  NULL
                                else 
                                  mainProcess$is_alive()
                                
                              },
                              valueFunc = function() { 
                                if(is.null(mainProcess))
                                  NULL
                                else
                                  mainProcess$is_alive()
                              })
#    logTimer <- reactiveFileReader(intervalMillis = 500, session=NULL, filePath = logFile, readFunc = readLines)
    output$logf <- renderPrint({
      req(!is.null(procTimer()))
      reactiveFileReader(intervalMillis = 500, session=NULL, filePath = logFile, readFunc = readLines)() 
      #logTimer()
    })
    
     
      
    
  })

ui <- fluidPage(
 
  asyncUI("myrun"),
  
)

server <- function(input, output, session) {
  asyncServer("myrun", logFile="count.log")
}

shinyApp(ui, server)

This runs a script count.tcsh that writes to a file counts.log. It displays the log in real time. count.tcsh script is

#!/bin/tcsh
echo "Begin script" >! count.log
foreach i (`seq 1 10`)
 sleep 1
 echo $i  seconds passed >> count.log
end

echo Finished script >> count.log

When I run it (in Linux), the version above does not display all the log file counts from 1 to 10, but (for a reason unknown to me) stops at count 2-3. If I use a variable inside renderPrint, it works just fine.

Myself I would prefer to be practical and write the cleanest easiest to follow code that I know how to do.
Though I do completely get the desire to understand the framework, and I have to admit I don't have the chops to do that for you ...

Of the different options I show below. 1 and 3 makes sense to me, and I have used them often in the past, and 2 seems to follow your imagined pattern, but I wouldn't have thought to use it.. maybe a lack of imagination on my part.. , and I don't have a clear reason for you as to why it doesn't work, you may need someone with knowledge of shiny internals to figure it for you, I expect there's something about it that does not reliably build the reactive graph.

Anyways, you have a solution so its not a big defeat, simply revert to using your logTimer object.

Example of problematic pattern:


library(shiny)

ui <- fluidPage(
  actionButton("mybtn","press"),
  verbatimTextOutput("mytext1"),
  verbatimTextOutput("mytext2"),
  verbatimTextOutput("mytext3")
)

server <- function(input, output, session) {
  
  some_named_reactive <- reactive({input$mybtn})
  
  output$mytext1 <- renderPrint({
    some_named_reactive()
  })
  
  output$mytext2 <- renderPrint({
    # best avoided
    reactive({input$mybtn})()
  })

  output$mytext3 <- renderPrint({
    input$mybtn
  })
}

shinyApp(ui, server)
1 Like

Thank you for the thinking.

By the way, your reprex is much clearer than my long example.