You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The default pool size respects the CPU limits of the process's cgroup. It
was one less than parallel::detectCores(), which reports the host's
cores, so in a container or on Posit Connect with a CPU quota or cpuset
the default pool started a daemon per host core. It is now one less than
the host's cores capped by the tightest cgroups v1 or v2 quota or cpuset
on the process or any ancestor cgroup (#17).
New vignette, vignette("extendedtask"), writes the surf forecast app with ExtendedTask and with shinyasync side by side, one piece at a time: the
pool, a fetch from an input, status and the previous value, a button with
cancel, superseded inputs, a chained task, side effects and fan-out, and
what the layer costs against ExtendedTask.
A running task no longer polls mirai::unresolved() every 100 ms. The poll
covered a promise notification that mirai can lose: its as.promise()
method checks unresolved() and then registers the notification, and a
task that completes in between never notifies. One check after
registration closes that window, so a task settles as soon as its result
arrives, with no timer. In shiny::testServer(), whose flush ends by
running due later callbacks, a task that finishes within the flush that
dispatched it now settles in that flush, where the poll left 100 ms of
grace; a test that reads the status or value of a quick task straight
after setInputs() should give the task some work. A test reproduces the
lost notification by widening the window. The race was fixed upstream in
nanonext 1.10.3.9000 (r-lib/mirai#656, r-lib/nanonext#363); the check is
skipped on that version and later, and goes once it is required (#16).
A connection opened in pool_async(everywhere = ) can be closed by a .Last function assigned in the same expression. R runs it when the
worker exits, on pool shutdown and when the app process dies, and the pool
does not wait for it. This is base R, so no teardown argument was added;
it is documented and tested (#25).
pool_async() gains everywhere, an expression evaluated once on every
worker when the pool starts, for data frames, models and connections that
every task needs. Objects it refers to are sent once and packages it uses
are attached; the names it creates are resident, so tasks no longer ship
them, and print() lists them on a resident line. The README documents
that shipped objects are otherwise serialized on every run (#15).
reactiveValAsync() is labelled with the name it is assigned to, as shiny::reactiveVal() is, so values can be told apart in reactlog (#21).
A task on a named mirai compute profile (mirai_async(.compute = "x")) no
longer starts the default pool (#20).
pool_async() documents what holds the pool outside an app: a script or
console call releases it when the next app in the process stops, or at
process exit (#19).
pool_async() called in server() and the first task in that session now
hold the pool once rather than twice; the counts balanced at session end
before, so this is an accounting change only (#18).
A reactiveAsync() waiting for an upstream async reactive now reports "running" while that upstream runs, so a status-driven spinner shows
during the whole refresh, and in mode = "latest" a run already computing
on the old upstream value is dropped instead of occupying a worker for a
result that would be discarded (#14).
A downstream gated with bindEvent() whose event fires while its upstream
async reactive is busy, or before it has started, now runs once the upstream
settles; cancel_async() drops the pending event, and so does an upstream
that stops without producing. Previously the event was always lost: the
halt inside bindEvent()'s isolate() registered no dependency, so
nothing re-ran the task (#11).
A name assigned inside an async expression now shadows the session object
only after its assignment, so data <- data() reads the reactive and ships
nothing. Previously the whole expression treated data as local, the
worker called utils::data() and the result was silently wrong, or failed
with "could not find function" for other names (#12).
mirai (>= 2.5.0) is now required. The code has used mirai::daemons_set()
(mirai 2.3.0) and the condition.class attribute on worker errors (mirai
2.5.0) since 0.2.0; with an older mirai a worker-side req() became a real
error instead of a silent halt (#13).