Skip to content

Commit

Permalink
The way too big commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rpodcast committed Sep 18, 2023
1 parent 4531c8f commit b4b9525
Show file tree
Hide file tree
Showing 40 changed files with 667 additions and 384 deletions.
46 changes: 26 additions & 20 deletions R/test_dependencies.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,46 @@ library(sys)


# define paths and constants
app_url <- "https://rsc.training.rstudio.com/bricktest/"
app_url <- "https://rsc.training.posit.co/brickapp_shell/"
recording_file <- "R/recording.log"

shinyloadtest::record_session(
app_link,
output_file = recording_file,
connect_api_key = Sys.getenv("RSCONNECT_KEY")
app_url,
output_file = recording_file
#connect_api_key = Sys.getenv("RSCONNECT_KEY")
)

# use the exec_wait function from sys
shinycannon_path <- "utils/shinycannon-1.1.3-dd43f6b.jar"

source(file.path(here::here(), "R", "shinycannon.R"))

shinycannon(
shinycannon_path,
recording_file,
app_url,
output_dir = "R/run1"
output_dir = "R/run1",
loaded_duration_minutes = 1,
log_level = "debug"
)

# baseline run
exec_wait(
cmd = "java",
args = c(
"-jar",
shinycannon_path,
recording_file,
app_link,
"--workers",
1,
"--loaded-duration-minutes",
3,
"--output-dir",
"R/run1",
"--overwrite-output"
shinyloadtest::record_session(
# baseline run
exec_wait(
cmd = "java",
args = c(
"-jar",
shinycannon_path,
recording_file,
app_link,
"--workers",
1,
"--loaded-duration-minutes",
3,
"--output-dir",
"R/run1",
"--overwrite-output"
)
)
)

Expand Down

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions _freeze/materials/d1-02-structure/index/execute-results/html.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"hash": "df5024907ac0a3253be0f2e64a57973a",
"result": {
"markdown": "---\ntitle: \"Application Structure\"\ntitle-slide-attributes:\n data-background-image: assets/img/lego_city.jpg\n data-background-size: contain\n data-background-opacity: \"0.3\"\nsubtitle: \"posit::conf(2023) <br> Shiny in Production: Tools & Techniques\"\nfooter: \"[{{< var workshop_short_url >}}]({{< var workshop_full_url >}})\"\nformat:\n revealjs:\n theme: [default, ../slides.scss] # moon= teal bg | dark\n scrollable: true\n incremental: false\n slide-number: c/t # c/t | c | h/v | h.v\n slide-tone: false #true\n code-line-numbers: false\n history: false\nfrom: markdown+emoji\nrevealjs-plugins:\n - codewindow\n---\n\n\n## It's Never Just Shiny\n\n... at least for production-quality apps!\n\n* External data sources\n* Connections to other execution backends\n* Additional R packages!\n\n\n# Application Structure Options\n\n## A Single Point: `app.R`\n\nPrototype apps can coast by with a single `app.R`\n\n* More inputs, visualizations, modules, tabs ...\n* Eventually the `app.R` almost explodes\n* Difficult to collaborate without conflicts\n\n## `R` Directory\n\n* Shiny supports auto-loading scripts in an `R` directory\n* Nested directories not supported\n* More information on the [App Formats](https://shiny.rstudio.com/articles/app-formats.html ) article\n\n## Enter the [`{golem}`](https://thinkr-open.github.io/golem/)\n\n> Opinionated framework for building production-grade Shiny applications as **R packages**\n\n* Scripts guide you with first steps akin to `{usethis}` & `{devtools}`\n* Encourages Shiny best practices (especially **modules**)\n* Streamlines deployment on multiple platforms\n\n::: {.notes}\n* Developed by Colin Fay & the ThinkR team in France\n* The moral of the stoary is that Shiny apps can get really big, really fast\n + We need to provide a lot of structure and guardrails; similar to what we do when developing *R packages*\n + This is why {golem} apps *are* R packages\n* Once you go {golem}, you never go back\n:::\n\n## {golem} project structure\n\n```\n├── DESCRIPTION\n├── NAMESPACE\n├── R\n│ ├── app_config.R\n│ ├── app_server.R\n│ ├── app_ui.R\n│ └── run_app.R\n├── dev\n│ ├── 01_start.R\n│ ├── 02_dev.R\n│ ├── 03_deploy.R\n│ └── run_dev.R\n├── inst\n│ ├── app\n│ │ └── www\n│ │ └── favicon.ico\n│ └── golem-config.yml\n└── man\n └── run_app.Rd\n```\n\n::: {.notes}\n* Looks a LOT like an R package's structure (because it is one!)\n* I want to just highlight the two directories `dev` and `R`\n + The scripts in `dev` have functions that safely do other things within the package (create scripts, add dependencies, etc.)\n + Some scripts in this directory will create other scripts in the `R` directory\n + The `R` directory is where all of the logic lives (your modules, custom functions, and UI/Server scripts)\n:::\n\n## Getting Started with {golem}\n\nUse helper functions in `dev/01_start.R` to...\n\n* Create `DESCRIPTION`, `README`, `LICENSE` (etc.) files\n* Use git, tests\n* Add your own favicon 🚀\n\n::: {.notes}\n- This file and the functions it includes help you manage things at the *project*-level\n:::\n\n## Developing with {golem}\n\nUse the helper functions in `dev/02_dev.R` to...\n\n* Add R package dependencies\n* Create custom functions\n* Add Shiny modules\n\n. . .\n\nAnd use `dev/run_dev.R` to run your app\n\n::: {.notes}\n- As you run these functions and watch in awe as your `DESCRIPTION` file changes automatically, as new .R files magically appear out of thin air that have already handled all of the tricky parts for you, you too will realize that {golem} is the ChatGPT of Shiny development\n:::\n\n## Deploying with {golem}\n\nUse the helper functions in `dev/03_deploy.R` to...\n\n* Check your R package ( `devtools::check()` )\n* Build your R package ( `R CMD build mypackage` )\n* Generate deployment files for\n + RStudio Connect\n + Shinyapps.io\n + Your own Shiny Server\n + Dockerized deployments (e.g., ShinyProxy)\n\n# All About Modules\n\n## What are Modules?\n\n. . .\n\n### Building blocks to compose any Shiny app out of smaller, more understandable pieces\n\n* Avoids namespace collisions when using same widget across different areas of your app\n* Allow you to encapsulate distinct app interfaces\n* Organize code into logical and easy-to-understand components\n* Facilitate collaboration\n\n## Sound familiar?\n\n* R functions also help avoid collisions in variable names with general R code\n* Essential for creating non-trivial and extensive workflows\n\n# Module Code Example\n\n## Anatomy of a Function (UI) {auto-animate=true}\n\n:::: {.columns}\n\n::: {.column width=\"60%\"}\n::: {.codewindow .r}\npicker.R\n```r\nset_picker_ui <- function() {\n tagList(\n selectInput(\n inputId = \"set_num\",\n label = \"Select a set\"\n choices = c(\"set1\", \"set2\"),\n selected = \"set1\",\n multiple = FALSE\n )\n )\n}\n```\n:::\n:::\n\n::: {.column width=\"40%\"}\n\n:::\n\n::::\n\n## Anatomy of a Module (UI) {auto-animate=true}\n\n:::: {.columns}\n\n::: {.column width=\"60%\"}\n\n::: {.codewindow .r}\nmod_picker.R\n```r\nset_picker_ui <- function(id) {\n ns <- NS(id)\n tagList(\n selectInput(\n inputId = ns(\"set_num\"),\n label = \"Select a set\"\n choices = c(),\n multiple = FALSE\n )\n )\n}\n```\n:::\n:::\n\n::: {.column width=\"40%\"}\n\n:::\n\n::::\n\n## Anatomy of a Module (UI)\n\n:::: {.columns}\n\n::: {.column width=\"60%\"}\n\n::: {.codewindow .r}\nmod_picker.R\n```{.r code-line-numbers=\"1,2,5\"}\nset_picker_ui <- function(id) {\n ns <- NS(id)\n tagList(\n selectInput(\n inputId = ns(\"set_num\"),\n label = \"Select a set\"\n choices = c(),\n multiple = FALSE\n )\n )\n}\n```\n:::\n:::\n\n::: {.column width=\"40%\"}\n\n* `id`: String to use for namespace\n* `ns <- NS(id)`: Create proper namespace function\n\n:::\n\n::::\n\n## Anatomy of a Module (Server) {auto-animate=true}\n\n::: {.codewindow .r}\nmod_picker.R\n```r\nset_picker_server <- function(input, output, session, sets_rv) {\n set_choices <- reactive({\n # do something with sets_rv\n })\n\n observeEvent(set_choices(), {\n req(set_choices())\n updateSelectInput(\n \"set_num\",\n choices = set_choices()\n )\n })\n}\n```\n:::\n\n## Anatomy of a Module (Server) {auto-animate=true}\n\n::: {.codewindow .r}\nmod_picker.R\n```r\nset_picker_server <- function(id, sets_rv) {\n moduleServer(\n id,\n function(input, output, session) {\n set_choices <- reactive({\n # do something with sets_rv\n })\n\n observeEvent(set_choices(), {\n req(set_choices())\n updateSelectInput(\n \"set_num\",\n choices = set_choices()\n )\n })\n }\n )\n}\n```\n:::\n\n\nMinimal changes necessary\n\n## Anatomy of a Module (Server) {auto-animate=true}\n\n:::: {.columns}\n\n::: {.column width=\"70%\"}\n\n```{.r code-line-numbers=\"1,2\"}\nset_picker_server <- function(id, sets_rv) {\n moduleServer(\n id,\n function(input, output, session) {\n set_choices <- reactive({\n # do something with sets_rv\n })\n\n observeEvent(set_choices(), {\n req(set_choices())\n updateSelectInput(\n \"set_num\",\n choices = set_choices()\n )\n })\n }\n )\n}\n```\n\n:::\n\n::: {.column width=\"30%\"}\n\n:thinking: `id`\n\n:::\n\n::::\n\n::: {style=\"font-size: 70%\"}\n`moduleServer()`: Encapsulate server-side logic with namespace applied.\n:::\n\n## Invoking Modules\n\n::: {.codewindow .r}\napp.R\n```{.r}\nlibrary(shiny)\nlibrary(bslib)\nui <- page_fluid(\n set_picker_ui(\"mod1\")\n)\n\nserver <- function(input, output, session) {\n sets_rv <- reactive({\n # processing\n })\n\n set_picker_server(\"mod1\", sets_rv)\n}\n\nshinyApp(ui, server)\n```\n:::\n\n## Giving and Receiving\n\n::: {.codewindow .r}\nmod_picker.R\n```r\nset_picker_ui <- function(id, label = \"Select a set\") {\n ns <- NS(id)\n tagList(\n selectInput(\n inputId = ns(\"set_num\"),\n label = label,\n choices = c(),\n multiple = FALSE\n )\n )\n}\n```\n:::\n\n::: {style=\"font-size: 80%\"}\n* Reasonable inputs: static values, vectors, flags\n* Avoid **reactive** parameters\n* Return value: `tagList()` of inputs, output placeholders, and other UI elements\n:::\n\n## Giving and Receiving\n\n::: {.codewindow .r}\nmod_picker.R\n```{.r}\nset_picker_server <- function(id, sets_rv) {\n moduleServer(\n id,\n function(input, output, session) {\n set_choices <- reactive({\n # do something with sets_rv\n })\n\n observeEvent(set_choices(), {\n req(set_choices())\n updateSelectInput(\n \"set_num\",\n choices = set_choices()\n )\n })\n }\n )\n}\n```\n:::\n\n::: {style=\"font-size: 80%\"}\nInput & return values can be a mix of static and **reactive** objects\n:::\n\n\n## To () or not to ()\n\n:::: {.columns}\n\n::: {.column width=\"45%\"}\n\n::: {.codewindow .r}\napp_server.R\n```{.r}\n# app server\nsets_rv <- reactive({\n # processing\n})\n\nset_picker_server(\"mod1\", sets_rv)\n```\n:::\n\n:::\n\n::: {.column width=\"55%\"}\n\n::: {.codewindow .r}\nmod_picker.R\n```{.r}\nset_picker_server <- function(id, sets_rv) {\n moduleServer(\n id,\n function(input, output, session) {\n # ...\n\n set_selection <- reactive({\n input$set_num\n })\n\n set_selection\n }\n )\n}\n```\n:::\n:::\n\n::::\n\n::: {style=\"font-size: 70%;\"}\n* Reactive parameters reference by **name**: `sets_rv`\n* Inside module, **invoke** reactive parameter as you would any other reactive in Shiny: `sets_rv()`\n* Any reactive(s) returned by module should also be reference by **name**: `set_selection`, ~~`set_selection()`~~\n:::\n\n::: footer\n:::\n\n# Code-Along {background-color=\"#17395c\"}\n\nAdd a new Shiny module to pick LEGO set themes\n\n* [Details](codealong-1.html){target=\"_blank\"}\n* Posit Cloud project: **Application Structure Code-along 1**\n\n## Your Turn: [Exercise 1](ex-1.html){target=\"_blank\"}\n\nCreate a new Shiny module with LEGO data metrics!\n\n* [Details](ex-1.html){target=\"_blank\"}\n* Posit Cloud project: **Application Structure Exercise 1**\n\n\n::: {.cell}\n::: {.cell-output-display}\n\n```{=html}\n<div class=\"countdown\" id=\"timer_41152904\" data-update-every=\"1\" tabindex=\"0\" style=\"right:0;bottom:0;\">\n<div class=\"countdown-controls\"><button class=\"countdown-bump-down\">&minus;</button><button class=\"countdown-bump-up\">&plus;</button></div>\n<code class=\"countdown-time\"><span class=\"countdown-digits minutes\">10</span><span class=\"countdown-digits colon\">:</span><span class=\"countdown-digits seconds\">00</span></code>\n</div>\n```\n\n:::\n:::\n\n\n\n# Dependency Management\n\n## Turned Upside-Down\n\nImagine your application is working great!\n\n<br>\n\n. . .\n\n:::: {.columns .v-center-container}\n\n::: {.column width=\"50%\"}\n\n```r\nupdate.packages(ask = FALSE)\nremotes::install_github(\"pkg\")\n```\n\n:::\n\n::: {.column width=\"50%}\n\n![](https://rfortherestofus.com/wp-content/uploads/2020/09/update-packages-prompt.png)\n\n:::\n\n::::\n\n## Turned Upside-Down\n\n:::: {.columns .v-center-container}\n\n::: {.column width=\"50%\"}\n\n`ggplot2` version `0.9.3`\n\n![](assets/img/computer_user_happy.png){width=\"60%\"}\n\n:::\n\n::: {.column width=\"50%\"}\n\n`ggplot2` version `1.0.0`\n\n![](http://i.giphy.com/RhEvCHIeZAZ6E.gif)\n\n:::\n\n::::\n\n## Take Control with [`{renv}`](https://rstudio.github.io/renv/)\n\n> Create **r**eproducible **env**ironments for your R projects.\n\n* Next generation of `{packrat}`\n* Isolated package library from rest of your system\n* Transfer projects to different collaborators / platforms\n* **Reproducible** package installation\n* Easily create new projects or convert existing projects with RStudio or built-in functions.\n\n## Under the Hood\n\nUpon initializing a project:\n\n1. Project-level `.Rprofile` to activate custom package library on startup\n1. Lockfile `renv.lock` to describe state of project library\n1. `renv/library` to hold private project library\n1. `renv/activate.R` performs activation\n\n## Develop a Routine\n\nSticking with `{renv}` will pay off (trust me)\n\n* Fair play to mix packages from CRAN, GitHub, and proprietary sources\n* Roll back when a package upgrade doesn't play nicely\n* **You** make the call when to update your library!\n",
"supporting": [],
"filters": [
"rmarkdown/pagebreak.lua"
],
"includes": {
"include-in-header": [
"<link href=\"../../site_libs/countdown-0.4.0/countdown.css\" rel=\"stylesheet\" />\n<script src=\"../../site_libs/countdown-0.4.0/countdown.js\"></script>\n"
],
"include-after-body": [
"\n<script>\n // htmlwidgets need to know to resize themselves when slides are shown/hidden.\n // Fire the \"slideenter\" event (handled by htmlwidgets.js) when the current\n // slide changes (different for each slide format).\n (function () {\n // dispatch for htmlwidgets\n function fireSlideEnter() {\n const event = window.document.createEvent(\"Event\");\n event.initEvent(\"slideenter\", true, true);\n window.document.dispatchEvent(event);\n }\n\n function fireSlideChanged(previousSlide, currentSlide) {\n fireSlideEnter();\n\n // dispatch for shiny\n if (window.jQuery) {\n if (previousSlide) {\n window.jQuery(previousSlide).trigger(\"hidden\");\n }\n if (currentSlide) {\n window.jQuery(currentSlide).trigger(\"shown\");\n }\n }\n }\n\n // hookup for slidy\n if (window.w3c_slidy) {\n window.w3c_slidy.add_observer(function (slide_num) {\n // slide_num starts at position 1\n fireSlideChanged(null, w3c_slidy.slides[slide_num - 1]);\n });\n }\n\n })();\n</script>\n\n"
]
},
"engineDependencies": {},
"preserve": {},
"postProcess": true
}
}
Loading

0 comments on commit b4b9525

Please sign in to comment.