Deployment & Administration

posit::conf(2023)
Shiny in Production: Tools & Techniques

Choose your Adventure

Posit Connect

Containers

Deployment Checklist

βœ… Create app.R in directory

βœ… Take note of any custom environment variables

βœ… Ensure DESCRIPTION is up-to-date with required packages

βœ… Remove outdated functions / scripts

03_deploy.R

## RStudio ----
## If you want to deploy on RStudio related platforms
golem::add_rstudioconnect_file()
golem::add_shinyappsio_file()
golem::add_shinyserver_file()

03_deploy.R

rsconnect::deployApp(
  appName = "legobricksapp",
  appTitle = desc::desc_get_field("Package"),
  appFiles = c(
    "R/",
    "inst/",
    "data/",
    "NAMESPACE",
    "DESCRIPTION",
    "app.R"
  ),
  appId = rsconnect::deployments(".")$appId,
  lint = FALSE,
  forceUpdate = TRUE
)

Code-Along

Deploy your application(s) to Posit Connect:

  • Use any of the applications from a previous exercise
  • Attempt both deployment types (push-button & {rsconnect})
  • Explore application settings in Posit Connect

Balancing Act

πŸ”Ό Max Processes

  • More resources dedicated to particular application
  • Potential for server overload

πŸ”Ό Min Processes

  • Resources dedicated even when app is idle
  • Potentially wasteful if app is not used concurrently often

Containers for Shiny Deployment

  • Anyone with a container runtime can execute your container without R on their system
    • Popular container runtimes: Docker, Podman, LXC
  • A multitude of web services offer serverless app deployments with containers
    • Bring your container image, they take care of the rest
    • Terrific reviews available at hosting.analythium.io

Coming soon: Container support for Posit Connect

Business Talk

You Might be Asked …

β€œHow many people used your app last year?”

β€œHow long are users on the app at a given time?”

β€œWhat is the return on investment (ROI) this app is bringing the company?”

NOT TODAY!

πŸ“¦ Introducing {connectapi}

R client for the Posit Connect Server API as well as helpful functions that utilize the client

Checklist:

βœ… Create API key for your Posit Connect account

βœ… Create .Renviron with following variables: CONNECT_SERVER, CONNECT_API_KEY

Introduce Yourself

library(connectapi)

client <- connect(
  server = Sys.getenv("CONNECT_SERVER"),
  api_key = Sys.getenv("CONNECT_API_KEY")
)

client
Posit Connect API Client: 
  Posit Connect Server: https://rsc.training.rstudio.com
  Posit Connect API Key: ***********FWxW
  • client is an R6 object representing the API client
  • Required parameter for many convenience functions

Know Yourself

my_guid <- user_guid_from_username(client, "rpodcast")

my_guid
[1] "47e1338f-54a8-4b0e-9b3c-e4380611b30f"
  • All content/users have a unique indentifier (guid)

Obtain (Your) Shiny Apps

library(dplyr)

meta_df <- get_content(client) |>
  filter(owner_guid == my_guid) |>
  select(guid, name, title)

meta_df
# A tibble: 27 Γ— 3
   guid                                 name            title          
   <chr>                                <chr>           <chr>          
 1 40dd2969-5d67-4940-89c4-08fe31fd1c74 brickapp        brickapp       
 2 fba6896e-49e4-45c6-856f-03a3bc4f498f legobricksapp   legobricks.app 
 3 626d6bb1-f36d-4c9b-bc9e-5cb44f46e698 hellogolem22    hellogolem2    
 4 6f8116dc-eabf-4a64-aacb-4aeffbb4eaa4 golembrochure2  golembrochure  
 5 a4e6809f-4858-4888-a848-94925d3df4a0 golembrochure   golembrochure  
 6 f268d424-a286-41b9-91f1-ae458797e64a golemhellolocal golemhellolocal
 7 4d9124a0-158b-4bd9-9b65-07b877db0906 test            test           
 8 c60de16e-0b29-4267-a2c5-0eb6815d7999 hellogolem3     hellogolem     
 9 2aec4c5b-144f-4a6c-8abf-7d07a17d78b2 hellogolem      hellogolem     
10 344b9f1b-ddbe-4145-a1f0-eb6608662f08 hellogolem2     hellogolem     
# β„Ή 17 more rows

Usage Metrics

Session durations for the legobricksapp:

app_guid <- "fba6896e-49e4-45c6-856f-03a3bc4f498f"

get_usage_shiny(
  client,
  content_guid = app_guid,
  limit = 5
  ) |>
  filter(!is.na(ended)) |>
  mutate(session_duration = ended - started) |>
  select(user_guid, session_duration)
# A tibble: 5 Γ— 2
  user_guid                            session_duration
  <chr>                                <drtn>          
1 47e1338f-54a8-4b0e-9b3c-e4380611b30f 10.933333 mins  
2 47e1338f-54a8-4b0e-9b3c-e4380611b30f  1.216667 mins  
3 47e1338f-54a8-4b0e-9b3c-e4380611b30f  4.733333 mins  
4 47e1338f-54a8-4b0e-9b3c-e4380611b30f  6.766667 mins  
5 47e1338f-54a8-4b0e-9b3c-e4380611b30f  1.183333 mins  

Usage Metrics

How many users visited legobricksapp in last 28 days?

app_guid <- "fba6896e-49e4-45c6-856f-03a3bc4f498f"
time_start <- Sys.Date() - lubridate::days(28)
get_usage_shiny(
  client,
  content_guid = app_guid,
  limit = 100,
  from = time_start
  ) |>
  pull(user_guid) |>
  unique() |>
  length()
[1] 4

Your Turn

Obtain metadata for your deployed application(s) on Posit Connect

  • Explore the data as you like!
05:00

Going Further with Metrics

Collection of interesting use cases available at github.com/sol-eng/connect-usage

  • Most-viewed content in last 30 days
  • Interactive dashboard of usage metrics
  • {connectViz}: Collection of customizable functions for visualizing content usage for an organization

Our Journey is Complete!

  • Robust app infrastructure with {golem}
  • Profiling your app with {profvis}
  • Solving performance bottlenecks
  • Assessing your app under high user load
  • Efficient app deployments and tuning
  • Obtaining usage metrics