From a644d2dd4c083c7596fd73edc0431bcb52811357 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 4 Sep 2024 14:26:57 -0400 Subject: [PATCH] feat: Slow down successive (same) exercise execution via throttle (#818) Co-authored-by: Garrick Aden-Buie Co-authored-by: Markus Konrad --- .github/workflows/R-CMD-check.yaml | 17 ++++++++--------- DESCRIPTION | 2 +- NEWS.md | 3 +++ R/exercise.R | 6 +++++- vignettes/articles/exercises.Rmd | 14 ++++++++++++++ 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index fea535cb8..973a73536 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -25,15 +25,14 @@ jobs: fail-fast: false matrix: config: - - {os: macOS-latest, r: 'release'} - - {os: windows-latest, r: 'release'} - - {os: windows-latest, r: '3.6'} - - {os: ubuntu-20.04, r: 'devel', http-user-agent: 'release'} - - {os: ubuntu-20.04, r: 'release'} - - {os: ubuntu-20.04, r: 'oldrel-1'} - - {os: ubuntu-20.04, r: 'oldrel-2'} - - {os: ubuntu-20.04, r: 'oldrel-3'} - - {os: ubuntu-20.04, r: 'oldrel-4'} + - { os: macOS-latest, r: "release" } + - { os: windows-latest, r: "release" } + - { os: ubuntu-20.04, r: "devel", http-user-agent: "release" } + - { os: ubuntu-20.04, r: "release" } + - { os: ubuntu-20.04, r: "oldrel-1" } + - { os: ubuntu-20.04, r: "oldrel-2" } + - { os: ubuntu-20.04, r: "oldrel-3" } + - { os: ubuntu-20.04, r: "oldrel-4" } env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} diff --git a/DESCRIPTION b/DESCRIPTION index db9ad5366..baed3eb42 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -73,5 +73,5 @@ Config/Needs/coverage: covr Config/Needs/website: pkgdown, tidyverse/tidytemplate Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 SystemRequirements: pandoc (>= 1.14) - http://pandoc.org diff --git a/NEWS.md b/NEWS.md index e89037a72..a2ca912a5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,9 @@ # learnr (development version) +- Added a new option, `tutorial.exercise.throttle`, to slow down successive exercise execution. This option should be set to the number of seconds a user will have to wait between performing code executions. The option defaults to 1 second to deter rapid code executions. To disable submission throttling, call `options(tutorial.exercise.throttle = 0)` within your setup chunk. (@internaut, #818) + - Removed dependency on ellipsis (@olivroy, #809) + - Added Norwegian translation contributed by @jonovik. (#806) # learnr 0.11.5 diff --git a/R/exercise.R b/R/exercise.R index a468af1fc..fbf280ffc 100644 --- a/R/exercise.R +++ b/R/exercise.R @@ -33,9 +33,13 @@ setup_exercise_handler <- function(exercise_rx, session) { # setup reactive values for return rv <- reactiveValues(triggered = 0, result = NULL) + # throttle option to slow down successive exercise execution requests + throttle_s <- getOption("tutorial.exercise.throttle", 1) # in seconds + if (is.numeric(throttle_s) && throttle_s > 0) { + exercise_rx <- throttle(exercise_rx, throttle_s * 1000) # in milliseconds + } # observe input observeEvent(exercise_rx(), { - # get exercise from app exercise <- exercise_rx() # Add tutorial information diff --git a/vignettes/articles/exercises.Rmd b/vignettes/articles/exercises.Rmd index 860247d4a..d842388e8 100644 --- a/vignettes/articles/exercises.Rmd +++ b/vignettes/articles/exercises.Rmd @@ -80,6 +80,20 @@ This option can also be set either globally or per-chunk: insert_snippet("exerciseeval") ``` +To prevent server overload caused by users rapidly clicking the "Run Code" button, you can set a delay between exercise code submissions using the `tutorial.exercise.throttle` option (in seconds). This will ensure that the same user can only start the evaluation of the same exercise per `tutorial.exercise.throttle` seconds. This option is set globally and the default is a throttle of of 1 second. + +```{r snippet-exercisethrottle, eval = FALSE} +# Set exercise submission throttle time to 5 seconds +options("tutorial.exercise.throttle" = 5) +``` + +To disable of this behavior, you can set the option to 0: + +```{r snippet-exercisethrottleoff, eval = FALSE} +# Disable exercise submission throttle +options("tutorial.exercise.throttle" = 0) +``` + ## Exercise Setup {#exercise-setup} Code chunks with `exercise=TRUE` are evaluated within standalone environments.