Skip to content

Run each run_r test on its own later loop - #279

Closed
jat255 wants to merge 1 commit into
mainfrom
jat255/267-temp-later-loop-in-tests
Closed

Run each run_r test on its own later loop#279
jat255 wants to merge 1 commit into
mainfrom
jat255/267-temp-later-loop-in-tests

Conversation

@jat255

@jat255 jat255 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

The R test suite spends about ten minutes doing nothing, and this makes it stop, without touching package code. Each run_r test now runs on its own later loop, so the timers a call leaves behind are discarded with the test instead of stalling later test files.

This is a workaround for the issue in #267 to get the tests running more quickly without touching production R code. When there's bandwidth for a proper review, #268 should get merged instead/in addition.

Summary

run_r leaks a 601 second reap timer and a 60 second timeout timer per call, and shiny::testServer() reads an output by spinning until later::loop_empty(), so the first such read after test-run-r.R waits for the farthest one. #267 has the mechanism and the measurements.

later::later() and later::later_fd() schedule onto later::current_loop(), so a test on its own loop cannot leak past itself. local_temp_loop() switches the current loop for the caller's scope and restores it on exit; every test in the file calls it first.

Review Notes

This is containment in the test suite, not a fix. The leak is untouched, #268 cancels the timers, and this branch should be reverted when that one lands.

local_temp_loop() calls the unexported later:::setCurrentRegistryId, for the reason given in the comment above it. Wrapping each body in the exported later::with_temp_loop() also works, but the 80 column limit then reindents all 22 test bodies. A test_that_local_loop() wrapper avoids that and was rejected because it breaks testthat's failure locations.

The new global-loop test skips in a full-suite run: test-chat.R already leaves callbacks on the global loop, so the test skips when the loop was busy at file load rather than fail for something it did not cause. Its companion, which asserts leftovers land on the loop the call ran on, always runs.

Testing

The whole suite passes in 50 seconds, against about eleven minutes before, and test-trajectory-review.R in the same session goes from 594 seconds to 1.4. R CMD check was not run locally, since no package code changed.

Refs #267

R changes

Nothing under pkg-r/R/ changed, so the package has no behaviour delta: no function was touched and no call site moved. The diff is one test file.

The helper is a withr-style local: record the current loop, create and enter a fresh one, defer restoring the old one and destroying the new one. Ordering is the part to check. withr::defer is LIFO and each test enters its loop before creating a worker, so the worker's deferred worker_close() runs while its loop is still alive; swapping those two lines in a test would tear the loop down underneath a closing worker.

Confinement rests on timers being scheduled through later::current_loop(), which is what the leak already depends on. I checked it rather than assuming: with the helper on only the tests using local_worker() the stall persisted, because several tests build a worker through test_agent(), and it went away once all 22 tests had it.

Worth your scrutiny: the later::: call is the one thing a later upgrade can break, and it would fail loudly rather than quietly resume leaking. No hand-written tests were deleted.

The R test suite spends about ten minutes idle. Every run_r call arms a reap
timer at commons.run_r_idle_timeout + 1 (601 seconds) and a timeout timer at
commons.run_r_timeout (60 seconds), and nothing cancels either. Only
test-run-r.R creates a worker, so it hands the global loop about 70 pending
callbacks. shiny::testServer() then reads an output through
shiny:::wait_for_it(), which spins until later::loop_empty() rather than
waiting on the output's own promise, so the first such read in
test-trajectory-review.R blocks for the full 601 seconds.

later::later() and later::later_fd() schedule onto later::current_loop(), so
giving each test its own loop confines the leftovers to a loop that is
destroyed when the test ends. later ships with_loop() but no local_ form, so
local_temp_loop() sets the current loop for the caller's scope and restores it
on exit.

The whole suite now runs in 50 seconds, and test-trajectory-review.R in 1.4
rather than 594.

This is containment in the test suite only. The leak itself is untouched, and
the production fix that cancels the timers is on
jat255/267-cancel-later-timers.

Refs #267
@jat255
jat255 marked this pull request as ready for review September 4, 2026 15:45
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Preview deployed to Connect (dogfood.team.pct.posit.it): https://dogfood.team.pct.posit.it/connect/#/apps/d7a36cae-8f27-448b-a478-61b81fbe3942/draft/367850

Deployed from commit b760bfb.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Preview deployed to Connect (connect.staging.pct.posit.it): https://connect.staging.pct.posit.it/connect/#/apps/ad662e1b-5048-4acc-9ad7-f9478c92274e/draft/2559

Deployed from commit b760bfb.

@jat255
jat255 requested a review from simonpcouch September 4, 2026 15:50
@jat255 jat255 added r Affects the R implementation tests Related to testing or the test suite labels Sep 4, 2026
local_temp_loop <- function(env = parent.frame()) {
old <- later::current_loop()
loop <- later::create_loop(parent = NULL)
later:::setCurrentRegistryId(loop$id)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not big on ::: here🙃 This will likely introduce an R CMD check NOTE.

If you're game to wait a day, I can have a fix for this in!

@jat255

jat255 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator Author

Closed in favor of #268

@jat255 jat255 closed this Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Cleaned up 1 preview bundle(s) on https://dogfood.team.pct.posit.it: 367850

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Cleaned up 1 preview bundle(s) on https://connect.staging.pct.posit.it: 2559

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r Affects the R implementation tests Related to testing or the test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants