Change default loading of `shiny` to specific `.libPaths()` on ShinyServer

I'm deploying a Shiny App on a shiny server maintained by my university, and there are many .libPaths() that contain different versions of packages.

> .libPaths()
[1] "/zeolite/rpauloo/R/x86_64-pc-linux-gnu-library/3.4"
[2] "/nfs/admin/software/xenial/system-gcc/R_libs"      
[3] "/usr/local/lib/R/site-library"                     
[4] "/usr/lib/R/site-library"                           
[5] "/usr/lib/R/library"  

When my shiny app boots up, shiny is loaded by default from .libPaths()[2] , which then imports R6 V.2.2.1 , also from this path.

However, my code depends on R6 >= V.2.2.2 , which I have in .libPaths()[1].

It would be simple enough to have my SysAdmin update R6 in .libPaths()[2] , but they cannot because other people's apps depend on the libraries on that path, and we don't want to break those.

I've tried:

  1. detaching R6 and loading it from .libPaths()[1]
detach("package:R6", unload=TRUE, force = TRUE, character.only = TRUE)
library(R6, lib.loc = "/zeolite/rpauloo/R/x86_64-pc-linux-gnu-library/3.4")  
  1. detaching shiny and loading it from .libPaths()[1]
detach("package:shiny", unload=TRUE, force = TRUE, character.only = TRUE)
library(shiny, lib.loc = "/zeolite/rpauloo/R/x86_64-pc-linux-gnu-library/3.4")  
  1. setting my .libPaths() from the start in the global.R file to only include the path I want.
.libPaths(.libPaths()[1])
  1. adding an etc folder under "/zeolite/rpauloo/R" that contains the following Rprofile.site file (advice from here):
.First <- function(){
  .libPaths("/zeolite/rpauloo/R/x86_64-pc-linux-gnu-library/3.4")
}

None of these approaches work. Why?

  1. R6 is an attached package, so it can't be unloaded.
  2. not sure why unloading/reloading shiny doesn't work
  3. Shiny Server loads shiny from .libPaths()[2] to begin with, before the global.R file is sourced, so setting libPaths() doesn't help.
  4. the Rprofile.site file is probably in the wrong directory, but putting it in an admin directory will mess with other apps

Question

How can I configure my shiny app to load shiny from a specific .libPath on startup?

Or have I mis-conceptualized the problem? Is there another way to go about this?

I would check out withr::with_libpaths and see if that can solve your issue.

I believe the core issue is coming from shiny depending on R6. I would install shiny directly into your first libpath and then only use that libpath when running your shiny app. You then have full control over which library versions are in that folder at execution time. (No need to depend on university maintained folder.)

Example:

withr:: with_libpaths("./local_folder", {
  shiny::runApp("app.R")
})

Thanks @barret! This is promising avenue forward, and you understand my problem.

I've already installed up-to-date versions of R6 and shiny in the libpath I want to use (.libPaths()[1]).

However, I'm using Shiny Server, so my app files (global, ui, server) live in the /srv directory and are automatically served to the web.

How do I integrate your withr solution into an app that's automatically served by Shiny Server?

As you've found out, you are stuck once the package is loaded. R doesn't behave well when unloading a pkg that another pkg uses directly.

I'm also guessing that you can't use callr::r to do calculations. This would launch a new process and you'd get control over which pkgs are loaded. But would only work as a on off calculator, not an interactive R session.

You said the Shiny Server is run by the university. I'm wondering if you can ask the admin to add this line to the config: (replace shiny with whichever user they are currently using)

location /zeolite/rpauloo  {
  run_as :HOME_USER: shiny;
}

Docs: https://support.rstudio.com/hc/en-us/articles/214771447-Shiny-Server-Administrator-s-Guide#run_as

This should run the apps in your folder under your user name, which should then load your ~/.Rprofile, which would allow you to set the appropriate .libPaths().

It is worth an ask to your admin. You're not asking for sudo privileges, just your existing user privileges.

If they already do this, make sure you have a ~/.Rprofile that adds your correct .libPath().

Thanks Barret! I'll ask my SysAdmin and report back. You are a saint. =)

One quick consideration: The app's files (global, server, ui, etc...) is actually stored in /srv/shiny-server/name_of_app. Does that change the 3 lines of code in the config?

1 Like

More docs: Shiny Server v1.5.21 Configuration Reference

A location configured to use user_dirs will allow users on the system to create and manage their own Shiny applications and make them available in their home directories. This directive will host any application stored in an eligible user's ~/ShinyApps directory publicly at a URL prefaced by their username.

This privilege can be restricted only to users of particular groups using the members_of restriction. For instance, the following configuration:

run_as :HOME_USER:;

# Define the root location
location / {
  user_dirs;
  
  # Only allow members of the 'shinyUsers' group to host personal applications.
  members_of shinyUsers;
}

will, for any user who is a member of the shinyUsers group, publicly host any Shiny application available in the user's ~/ShinyApps directory. For instance, if a user named tina who is a member of the shinyUsers group, has /home/tina as a home directory, and has an application called shinyApp1 in /home/tina/ShinyApps/ , that application would be available on this server at the URL http://server.com/tina/shinyApp1 . Any other application in /home/tina/ShinyApps/ would also be publically available at a similar URL.

My understanding of this is that if they add rpauloo to the shinyUsers group on the university server, you could host an app that is located in your personal home directory, /zeolite/rpauloo/shinyApps/RichShinyApp/{app,ui,server}.R. This would mean permissions wouldn't need to be altered for any existing apps currently in place (brownie points for the admin) and it would give you full control over your personal app and your .Rprofile. Your app should then be reachable at http://server.com/rpauloo/RichShinyApp once deployed.

1 Like

I actually think it's simpler than all that; you should be able to put an .Rprofile file directly in your app directory, and it will be respected, no matter what user launches it. No need to modify the Shiny Server config or anything. This is in fact how packrat works.

2 Likes

Hi @jcheng, thanks for taking an interest in this question. I tried putting both .Rprofile and Rprofile.site files in my home directory and the app directory (along with the global, server, ui files) that set the .libPaths() like so:

.First <- function(){ .libPaths(.libPaths()[1]) }

These don't fix the underlying error. R6 is still loaded from .libPaths()[2], and throws: ... namespace 'R6' 2.2.1 is already loaded, but >= 2.2.2 is required...

I'm working with my SysAdmin on this now, and will report a working solution when we find one.

Any advice in the interim is very much appreciated. Thanks for your consideration.

This issue is resolved. @jcheng's suggestion to add a .Rprofile file in the app directory that respecifies the libPaths works just fine.

In Rprofile:

.libPaths( c("/zeolite/rpauloo/R/x86_64-pc-linux-gnu-library/3.4/", .libPaths()))

Thanks @jcheng and @barret for your help in troubleshooting this issue!

1 Like

If your question's been answered (even by you!), would you mind choosing a solution? It helps other people see which questions still need help, or find solutions if they have similar problems. Here’s how to do it:

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