From 627301f12fa0d8b04a02da5a52c93981c297b8f9 Mon Sep 17 00:00:00 2001 From: Eric Nantz Date: Mon, 18 Sep 2023 09:42:16 -0400 Subject: [PATCH] clarify project IDs for exercises --- .../codealong-2/execute-results/html.json | 8 +++++--- .../d1-03-performance/ex-1/execute-results/html.json | 8 +++++--- materials/d1-03-performance/codealong-2.qmd | 4 ++++ materials/d1-03-performance/ex-1.qmd | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/_freeze/materials/d1-03-performance/codealong-2/execute-results/html.json b/_freeze/materials/d1-03-performance/codealong-2/execute-results/html.json index a99eb2e..03cce7d 100644 --- a/_freeze/materials/d1-03-performance/codealong-2/execute-results/html.json +++ b/_freeze/materials/d1-03-performance/codealong-2/execute-results/html.json @@ -1,8 +1,10 @@ { - "hash": "c12dcd124a82cea6178e9a18ef6d6d65", + "hash": "9ca299b36097116185a2b12ce0d94b06", "result": { - "markdown": "---\ntitle: Asynchronous Processing of LEGO Model Prediction\nformat:\n html:\n code-line-numbers: false\n execute:\n echo: true\n eval: false\n---\n\n\n## Requirements\n\nThe current version of our Shiny application contains a module for generating predictions of the number of LEGO parts in a set using the number of unique colors and number of unique part categories. The API is executed and processed using the [`{httr2}`](https://httr2.r-lib.org/) package. Here is the function wrapping the API execution:\n\n\n::: {.cell}\n\n```{.r .cell-code}\n#' @importFrom httr2 request req_body_json req_perform resp_body_json\nrun_prediction <- function(df, endpoint_url, back_transform = TRUE, round_result = TRUE) {\n # create request object\n req <- request(endpoint_url)\n\n # perform request\n resp <- req |>\n req_body_json(df) |>\n req_perform()\n\n # extract predictions from response\n pred_values <- resp_body_json(resp)$.pred |> unlist()\n\n # back-transform log10 value of predicted number of parts if requested\n if (back_transform) {\n pred_values <- 10 ^ pred_values\n }\n\n # round result up to nearest integer if requested\n if (round_result) pred_values <- ceiling(pred_values)\n\n # append predictions to supplied data frame\n dplyr::mutate(df, predicted_num_parts = pred_values)\n}\n```\n:::\n\n\nUnfortunately, the prediction API call takes a bit of time to execute due to some **extremely sophisticated processing** 😅. As a result, any interactions within the application will not be processed until the prediction call completes. Our goal is to convert the prediction processing from *synchronous* to *asynchronous* using `{crew}`\n\n## Plan\n\n1. Establish reactive values for tracking the status of the prediction calls\n1. Create a new controller to launch new R processes when new prediction tasks are launched\n1. Modify the existing `observeEvent` to push the prediction task to the controller, ensuring the key objects and required packages are passed on to the controller.\n1. Create a poll that's invalidated every 100 milliseconds to query the status of the submitted tasks in the controller and update the prediction result reactive value when complete.\n\n## Solution \n\nFirst we create the following `reactiveVal` objects to keep track of the prediction state:\n\n\n::: {.cell}\n\n```{.r .cell-code}\npred_status <- reactiveVal(\"No prediction submitted yet.\")\npred_poll <- reactiveVal(FALSE)\n```\n:::\n\n\nNext we set up a new controller:\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# establish async processing with crew\ncontroller <- crew_controller_local(workers = 4, seconds_idle = 10)\ncontroller$start()\n\n# make sure to terminate the controller on stop #NEW\nonStop(function() controller$terminate())\n```\n:::\n\n\nInside the `observeEvent` for the user clicking the prediction button, we update the logic to push the prediction task to the controller:\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncontroller$push(\n command = run_prediction(df),\n data = list(\n run_prediction = run_prediction,\n df = pred_data_rv$data\n ),\n packages = c(\"httr2\", \"dplyr\")\n)\n\npred_poll(TRUE)\n```\n:::\n\n\nLastly, we create a new `observe` block that periodically checks whether the running `{crew}` tasks have completed, ensuring that this is only executed when a prediction has been launched:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nobserve({\n req(pred_poll())\n\n invalidateLater(millis = 100)\n result <- controller$pop()$result\n\n if (!is.null(result)) {\n pred_data_rv$data <- result[[1]]\n print(controller$summary()) \n }\n\n if (isFALSE(controller$nonempty())) {\n pred_status(\"Prediction Complete\")\n pred_poll(controller$nonempty())\n removeNotification(id = \"pred_message\")\n }\n})\n```\n:::\n", - "supporting": [], + "markdown": "---\ntitle: Asynchronous Processing of LEGO Model Prediction\nformat:\n html:\n code-line-numbers: false\n execute:\n echo: true\n eval: false\n---\n\n\n## Access Instructions\n\nThe project used for this particular exercise is hosted on [Posit Cloud](https://posit.cloud) in this [space](https://posit.cloud/spaces/400774/join?access_code=DDgV_peF5WCCCpB5JHjQtMN2aHByWoNF0k5p8Wp7). The project for this exercise is called **Performance Code-along 2**.\n\n## Requirements\n\nThe current version of our Shiny application contains a module for generating predictions of the number of LEGO parts in a set using the number of unique colors and number of unique part categories. The API is executed and processed using the [`{httr2}`](https://httr2.r-lib.org/) package. Here is the function wrapping the API execution:\n\n\n::: {.cell}\n\n```{.r .cell-code}\n#' @importFrom httr2 request req_body_json req_perform resp_body_json\nrun_prediction <- function(df, endpoint_url, back_transform = TRUE, round_result = TRUE) {\n # create request object\n req <- request(endpoint_url)\n\n # perform request\n resp <- req |>\n req_body_json(df) |>\n req_perform()\n\n # extract predictions from response\n pred_values <- resp_body_json(resp)$.pred |> unlist()\n\n # back-transform log10 value of predicted number of parts if requested\n if (back_transform) {\n pred_values <- 10 ^ pred_values\n }\n\n # round result up to nearest integer if requested\n if (round_result) pred_values <- ceiling(pred_values)\n\n # append predictions to supplied data frame\n dplyr::mutate(df, predicted_num_parts = pred_values)\n}\n```\n:::\n\n\nUnfortunately, the prediction API call takes a bit of time to execute due to some **extremely sophisticated processing** 😅. As a result, any interactions within the application will not be processed until the prediction call completes. Our goal is to convert the prediction processing from *synchronous* to *asynchronous* using `{crew}`\n\n## Plan\n\n1. Establish reactive values for tracking the status of the prediction calls\n1. Create a new controller to launch new R processes when new prediction tasks are launched\n1. Modify the existing `observeEvent` to push the prediction task to the controller, ensuring the key objects and required packages are passed on to the controller.\n1. Create a poll that's invalidated every 100 milliseconds to query the status of the submitted tasks in the controller and update the prediction result reactive value when complete.\n\n## Solution \n\nFirst we create the following `reactiveVal` objects to keep track of the prediction state:\n\n\n::: {.cell}\n\n```{.r .cell-code}\npred_status <- reactiveVal(\"No prediction submitted yet.\")\npred_poll <- reactiveVal(FALSE)\n```\n:::\n\n\nNext we set up a new controller:\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# establish async processing with crew\ncontroller <- crew_controller_local(workers = 4, seconds_idle = 10)\ncontroller$start()\n\n# make sure to terminate the controller on stop #NEW\nonStop(function() controller$terminate())\n```\n:::\n\n\nInside the `observeEvent` for the user clicking the prediction button, we update the logic to push the prediction task to the controller:\n\n\n::: {.cell}\n\n```{.r .cell-code}\ncontroller$push(\n command = run_prediction(df),\n data = list(\n run_prediction = run_prediction,\n df = pred_data_rv$data\n ),\n packages = c(\"httr2\", \"dplyr\")\n)\n\npred_poll(TRUE)\n```\n:::\n\n\nLastly, we create a new `observe` block that periodically checks whether the running `{crew}` tasks have completed, ensuring that this is only executed when a prediction has been launched:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nobserve({\n req(pred_poll())\n\n invalidateLater(millis = 100)\n result <- controller$pop()$result\n\n if (!is.null(result)) {\n pred_data_rv$data <- result[[1]]\n print(controller$summary()) \n }\n\n if (isFALSE(controller$nonempty())) {\n pred_status(\"Prediction Complete\")\n pred_poll(controller$nonempty())\n removeNotification(id = \"pred_message\")\n }\n})\n```\n:::\n", + "supporting": [ + "codealong-2_files" + ], "filters": [ "rmarkdown/pagebreak.lua" ], diff --git a/_freeze/materials/d1-03-performance/ex-1/execute-results/html.json b/_freeze/materials/d1-03-performance/ex-1/execute-results/html.json index 8516a04..9928e30 100644 --- a/_freeze/materials/d1-03-performance/ex-1/execute-results/html.json +++ b/_freeze/materials/d1-03-performance/ex-1/execute-results/html.json @@ -1,8 +1,10 @@ { - "hash": "c5d56b9141dff51b58a10ea0827719ca", + "hash": "57d9b10d138d0a21c0eeb085d17a8d7d", "result": { - "markdown": "---\ntitle: \"Profile the LEGO Bricks App\"\n---\n\n\n## Access Instructions\n\nThe project used for this particular exercise is hosted on [Posit Cloud](https://posit.cloud) in this [space](https://posit.cloud/spaces/400774/join?access_code=DDgV_peF5WCCCpB5JHjQtMN2aHByWoNF0k5p8Wp7). The project for this exercise is called **performance-exercise1**.\n\n## Setup\n\nUsing what you just learned about the [`{profvis}`](http://rstudio.github.io/profvis/examples.html#example-3---profiling-a-shiny-application), your task is to run the profiler for the LEGO Bricks application contained in this project. Recall that to run the profiler in a Shiny app created with `{golem}`, change the `run_app()` call at the end of the `dev/run_dev.R` script to the following:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nprofvis::profvis({\n print(run_app())\n})\n```\n:::\n\n\nOnce the application is open, try changing a couple of the inputs contained in the sidebar. Once the outputs in the app refresh, close the profiler by stopping the R process in the R console. You should now see the `{profvis}` report appear as a new tab in your web browser.\n\n## Questions\n\n* Are you able to identify any performance bottlenecks in the application?\n* If so, can you think of ways to fix the issues?", - "supporting": [], + "markdown": "---\ntitle: \"Profile the LEGO Bricks App\"\n---\n\n\n## Access Instructions\n\nThe project used for this particular exercise is hosted on [Posit Cloud](https://posit.cloud) in this [space](https://posit.cloud/spaces/400774/join?access_code=DDgV_peF5WCCCpB5JHjQtMN2aHByWoNF0k5p8Wp7). The project for this exercise is called **Performance Exercise 1**.\n\n## Setup\n\nUsing what you just learned about the [`{profvis}`](http://rstudio.github.io/profvis/examples.html#example-3---profiling-a-shiny-application), your task is to run the profiler for the LEGO Bricks application contained in this project. Recall that to run the profiler in a Shiny app created with `{golem}`, change the `run_app()` call at the end of the `dev/run_dev.R` script to the following:\n\n\n::: {.cell}\n\n```{.r .cell-code}\nprofvis::profvis({\n print(run_app())\n})\n```\n:::\n\n\nOnce the application is open, try changing a couple of the inputs contained in the sidebar. Once the outputs in the app refresh, close the profiler by stopping the R process in the R console. You should now see the `{profvis}` report appear as a new tab in your web browser.\n\n## Questions\n\n* Are you able to identify any performance bottlenecks in the application?\n* If so, can you think of ways to fix the issues?", + "supporting": [ + "ex-1_files" + ], "filters": [ "rmarkdown/pagebreak.lua" ], diff --git a/materials/d1-03-performance/codealong-2.qmd b/materials/d1-03-performance/codealong-2.qmd index f91c260..137ca04 100644 --- a/materials/d1-03-performance/codealong-2.qmd +++ b/materials/d1-03-performance/codealong-2.qmd @@ -8,6 +8,10 @@ format: eval: false --- +## Access Instructions + +The project used for this particular exercise is hosted on [Posit Cloud](https://posit.cloud) in this [space](https://posit.cloud/spaces/400774/join?access_code=DDgV_peF5WCCCpB5JHjQtMN2aHByWoNF0k5p8Wp7). The project for this exercise is called **Performance Code-along 2**. + ## Requirements The current version of our Shiny application contains a module for generating predictions of the number of LEGO parts in a set using the number of unique colors and number of unique part categories. The API is executed and processed using the [`{httr2}`](https://httr2.r-lib.org/) package. Here is the function wrapping the API execution: diff --git a/materials/d1-03-performance/ex-1.qmd b/materials/d1-03-performance/ex-1.qmd index 9189d92..a69cc8a 100644 --- a/materials/d1-03-performance/ex-1.qmd +++ b/materials/d1-03-performance/ex-1.qmd @@ -4,7 +4,7 @@ title: "Profile the LEGO Bricks App" ## Access Instructions -The project used for this particular exercise is hosted on [Posit Cloud](https://posit.cloud) in this [space](https://posit.cloud/spaces/400774/join?access_code=DDgV_peF5WCCCpB5JHjQtMN2aHByWoNF0k5p8Wp7). The project for this exercise is called **performance-exercise1**. +The project used for this particular exercise is hosted on [Posit Cloud](https://posit.cloud) in this [space](https://posit.cloud/spaces/400774/join?access_code=DDgV_peF5WCCCpB5JHjQtMN2aHByWoNF0k5p8Wp7). The project for this exercise is called **Performance Exercise 1**. ## Setup