I am developing a Shiny application where I need to score a series of articles asynchronously by calling an external API using my own package. I aim to run multiple promises in parallel to enhance performance and wish to update a progress bar after each promise completes.
Here's the code in the server side of the app, inside a withProgress() block:
# Set up reactive values
articles <- reactiveVal()
articles(get_articles())
scored_articles <- reactiveVal()
# Set up parallel environment
old_plan <- future::plan()
future::plan(future::multisession)
on.exit(future::plan(old_plan), add = TRUE)
# Progress bar parameters init
incProgress(.5)
batch_size <- 20
tot_items <- articles() |> nrow()
# Score articles
promises <- articles() |>
group_by(grp = ceiling(row_number()/batch_size)) |> # Split dataset into chunks
group_split() |>
furrr::future_map(\(df) {
message("Promise launched")
promises::future_promise({
score <- get_llm_score(df)
incProgress(.5 / (tot_items/batch_size))
score
})
})
# Solve the promises
promises::promise_all(.list = promises) |>
promises::then(function(result) {
# post-processing the result
result |> bind_rows() |>
scored_articles()
}) |>
promises::catch(function(error) {
message(error)
showNotification("An error occurred", type = "error")
})
Something doesn't work in this implementation. This is what happens:
- The bar gets stuck at 50% (the value that it should have before starting the promise).
- The "Promise launched" messages are triggered much later, presumably AFTER the call to get_llm_score() has been completed, instead of before.
- The progress bar then disappears. My hypothesis is that it gets updated all at once after all the promises have been fulfilled.
- Then nothing happens. The app should row bind the loop output and put it into scored_articles() which should trigger the rendering of the table.
What am I doing wrong? is this the correct way to run a repeated process in parallel? how should I implement it in order to have a starting message before my function is run and a progress update once it's done?
Any insights or recommendations would be greatly appreciated.