Skip to content

turbo-tasks: prioritize recomputed tasks with Recomputation priority#93876

Open
sokra wants to merge 2 commits into
canaryfrom
sokra/recomputation-priority
Open

turbo-tasks: prioritize recomputed tasks with Recomputation priority#93876
sokra wants to merge 2 commits into
canaryfrom
sokra/recomputation-priority

Conversation

@sokra
Copy link
Copy Markdown
Member

@sokra sokra commented May 15, 2026

What?

Introduces a new Recomputation priority in TaskPriority that schedules recomputed tasks (tasks re-run because their output or cell wasn't available when read) ahead of all invalidation phases. Also documents every TaskExecutionReason variant and removes the unused Local variant.

Why?

When a task is recomputed because a downstream consumer needed its output/cell, that recomputation should run before lower-priority invalidations so the consumer can make progress. Previously these recomputations were scheduled with Initial priority, which placed them alongside fresh work and behind ongoing invalidation phases, hurting latency for the task actually being awaited.

Care is needed so the new priority doesn't spread virally: any invalidation triggered during a Recomputation task must not itself be tagged Recomputation, otherwise the priority would leak across the graph and break ordering. The change therefore resets the priority to Initial for invalidations triggered from a recomputation context.

How?

  • turbo-tasks/src/manager.rs: Add TaskPriority::Recomputation variant, ordered before Invalidation. Update Display and update impls.
  • turbo-tasks-backend/src/backend/mod.rs: Schedule output-not-available and cell-not-available recomputations with TaskPriority::Recomputation instead of Initial.
  • turbo-tasks-backend/src/backend/operation/invalidate.rs: When make_task_dirty_internal runs under a parent task with Recomputation priority, downgrade the propagated priority to Initial so the recomputation marker does not spread. Also tighten the "already dirty" branch so a stored Initial priority is always replaced by a more specific parent priority.
  • turbo-tasks/src/task_execution_reason.rs: Document each variant and drop the unused Local variant (and its as_str arm).

Closes NEXT-

sokra added 2 commits May 15, 2026 17:16
Adds a `Recomputation` variant to `TaskPriority` that sorts before
all invalidation phases, ensuring recomputed tasks run first. Tasks
invalidated during recomputation reset to `Initial` to prevent the
recomputation order from spreading virally and breaking ordering.
@sokra sokra force-pushed the sokra/recomputation-priority branch from 53c9d96 to e1343eb Compare May 15, 2026 16:02
@sokra sokra requested a review from lukesandberg May 15, 2026 16:03
@sokra sokra marked this pull request as ready for review May 15, 2026 16:03
@@ -1,21 +1,35 @@
#[derive(Debug)]
pub enum TaskExecutionReason {
/// A root task was initially scheduled and is executed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it isn't necessarily a 'root' task, right?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

or is this the difference between Initial and ActivateInitial?

maybe this should be RootInitial?

/// output yet), so it was scheduled and executed to produce the task output.
/// Or a task was called inside of a turbo_tasks::run closure for the first time (no output
/// yet), so it was scheduled and executed to produce the task output.
Connect,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this one is kind of confusing to me... this could be a new root task connecting a child?

but how is that different from Initial. i see that this is set if a child is connected with no parent, so isn't that limited to root tasks

@github-actions
Copy link
Copy Markdown
Contributor

Stats from current PR

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 813ms 812ms ▂▅▄██
Cold (Ready in log) 808ms 810ms ▅▁▅▇▄
Cold (First Request) 1.294s 1.287s ▄▁▄█▅
Warm (Listen) 813ms 811ms ▁▆▁█▆
Warm (Ready in log) 811ms 808ms ▇▁██▄
Warm (First Request) 646ms 647ms ▆▁██▄
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 812ms 811ms ▁▇▇▇▅
Cold (Ready in log) 787ms 788ms ▄▅▇█▄
Cold (First Request) 3.261s 3.255s ▄▄▆█▃
Warm (Listen) 811ms 810ms ▁▅▅▅▅
Warm (Ready in log) 788ms 789ms ▄▅▅█▄
Warm (First Request) 3.262s 3.272s ▆▄▄█▄

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 4.899s 4.886s ▄▁▃█▃
Cached Build 4.925s 4.890s ▄▁▆█▄
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 24.133s 24.007s ▁▂█▅█
Cached Build 24.237s 24.195s ▃▄█▇▂
node_modules Size 506 MB 506 MB ▁▁▁▁▁
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
04hm05ar7kldw.js gzip 5.73 kB N/A -
0bonocw_gqjqz.js gzip 156 B N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0dvitrl5zg37g.js gzip 8.82 kB N/A -
0ge802sebgoxs.js gzip 154 B N/A -
0rrx2nt9ziwqd.js gzip 153 B N/A -
0sf7ysou-72zd.js gzip 8.71 kB N/A -
0ut-_tdusoc4k.js gzip 65.6 kB N/A -
0wj045gch1h53.js gzip 158 B N/A -
157abun3hwc_s.js gzip 10.3 kB N/A -
17hnwtgojusdj.js gzip 155 B N/A -
1d2gtywb-5p_7.js gzip 156 B N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1evlt1ko-tqhp.js gzip 155 B N/A -
1jj68jv9537mc.js gzip 13.8 kB N/A -
1jpaub6y8xlfr.js gzip 2.3 kB N/A -
1ot0mvscrc_uf.js gzip 233 B N/A -
1usbsn3vadnmw.js gzip 152 B N/A -
2_m3xv2uq3sjc.js gzip 1.46 kB N/A -
24y34mwgrkqp4.js gzip 8.78 kB N/A -
27eg7sxq5mk_q.js gzip 156 B N/A -
284i3wear-lyg.js gzip 155 B N/A -
2c-fd4y1zozz8.js gzip 8.79 kB N/A -
2d7416h_xd36x.js gzip 8.71 kB N/A -
2g21ny1t2kw37.js gzip 7.61 kB N/A -
2i8sn3m1qpu4_.js gzip 154 B N/A -
2iqdnxyc5-kp0.js gzip 70.9 kB N/A -
2liogep5ypr09.js gzip 160 B N/A -
2lyuhit6rn8fy.js gzip 9.44 kB N/A -
2p2xgspe77mv3.js gzip 50.2 kB N/A -
2q0gr8wfr3jwl.js gzip 8.77 kB N/A -
2t9e75oz6r0zp.js gzip 8.76 kB N/A -
2uku_olcn15b7.js gzip 8.79 kB N/A -
30r8mm-46bdqy.js gzip 220 B 220 B
38oxsi-2338b1.js gzip 168 B N/A -
3c1jdxkzlb8oq.js gzip 12.9 kB N/A -
3inab2jybr4k9.js gzip 450 B N/A -
3jkm5tdjvaf_q.js gzip 13.1 kB N/A -
3mt67agm5wp40.js gzip 10.6 kB N/A -
3saabek4kohwi.js gzip 10 kB N/A -
4189xmby9yu1p.js gzip 13.6 kB N/A -
turbopack-1f..2ev9.js gzip 4.2 kB N/A -
turbopack-1p..kv4s.js gzip 4.2 kB N/A -
turbopack-1x..ymh3.js gzip 4.2 kB N/A -
turbopack-20..y4xy.js gzip 4.2 kB N/A -
turbopack-24..8nhk.js gzip 4.2 kB N/A -
turbopack-29..myjv.js gzip 4.19 kB N/A -
turbopack-2i..0h1n.js gzip 4.2 kB N/A -
turbopack-2i..yytq.js gzip 4.2 kB N/A -
turbopack-2n..8q96.js gzip 4.2 kB N/A -
turbopack-2t..bhx8.js gzip 4.21 kB N/A -
turbopack-38..n694.js gzip 4.2 kB N/A -
turbopack-3f..hnl5.js gzip 4.2 kB N/A -
turbopack-3y..8u5u.js gzip 4.18 kB N/A -
turbopack-43..6pwj.js gzip 4.2 kB N/A -
0_i7nqgx23st7.js gzip N/A 10 kB -
06puhytyxk31p.js gzip N/A 8.82 kB -
0bq5-83alcpe4.js gzip N/A 152 B -
0d6qosyqx3umb.js gzip N/A 155 B -
0j42f9zonj0wd.js gzip N/A 13 kB -
0m34gln_kt4fg.js gzip N/A 5.73 kB -
0onx8mzqg8i3u.js gzip N/A 156 B -
1-ewshnd9bzgq.js gzip N/A 50.2 kB -
14kwvdg9vf7nu.js gzip N/A 70.9 kB -
1g3q1ww01thnl.js gzip N/A 2.3 kB -
1hraqxuiymq6v.js gzip N/A 8.79 kB -
1l9un1sl77287.js gzip N/A 1.46 kB -
1lonym6dfvlth.js gzip N/A 155 B -
21-eavqb1k_36.js gzip N/A 13.9 kB -
2147zgtf14z-q.js gzip N/A 234 B -
23bz3xsg-5-1s.js gzip N/A 8.71 kB -
27441mytv7pbm.js gzip N/A 9.43 kB -
28g0r5aod42qc.js gzip N/A 155 B -
2cjkwjgm1zcfs.js gzip N/A 8.71 kB -
2kcuwbgnu4ko6.js gzip N/A 161 B -
2scd8zaoyb8md.js gzip N/A 8.79 kB -
2st_qs6p_9us0.js gzip N/A 13.1 kB -
2zo2exm1d8qj1.js gzip N/A 13.6 kB -
3-_hfgcp96285.js gzip N/A 154 B -
35745aboz61if.js gzip N/A 157 B -
3f710q6kll2xn.js gzip N/A 7.61 kB -
3hn75zuxly9az.js gzip N/A 10.3 kB -
3hqh7m128tvsn.js gzip N/A 8.77 kB -
3hqti_t-zy1x4.js gzip N/A 449 B -
3lh-i1b9s84cd.js gzip N/A 156 B -
3mnawenie1flm.js gzip N/A 8.76 kB -
3sr5ob3duztqs.js gzip N/A 154 B -
3sythmw-4cn1i.js gzip N/A 169 B -
3ubsozlu6zs38.js gzip N/A 10.6 kB -
3wuicn9beco_z.js gzip N/A 65.6 kB -
43b04vw4l4o3u.js gzip N/A 155 B -
43iwfqjnx1cy_.js gzip N/A 8.78 kB -
44uaeayqp3xyx.js gzip N/A 159 B -
turbopack-0o..f8yc.js gzip N/A 4.2 kB -
turbopack-0q..4cfi.js gzip N/A 4.2 kB -
turbopack-0r..nu40.js gzip N/A 4.18 kB -
turbopack-0z..izje.js gzip N/A 4.2 kB -
turbopack-10..6ob-.js gzip N/A 4.2 kB -
turbopack-16..-uwu.js gzip N/A 4.21 kB -
turbopack-1e..-gur.js gzip N/A 4.2 kB -
turbopack-1v..0so-.js gzip N/A 4.2 kB -
turbopack-1w..krei.js gzip N/A 4.2 kB -
turbopack-2c..nu9o.js gzip N/A 4.2 kB -
turbopack-3a..zg-c.js gzip N/A 4.2 kB -
turbopack-3h..b2g6.js gzip N/A 4.2 kB -
turbopack-3w..ij0a.js gzip N/A 4.2 kB -
turbopack-3y..837u.js gzip N/A 4.2 kB -
Total 469 kB 469 kB ⚠️ +80 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 715 B 718 B
Total 715 B 718 B ⚠️ +3 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 431 B 432 B
Total 431 B 432 B ⚠️ +1 B

📦 Webpack

Client

Main Bundles
Canary PR Change
2258-HASH.js gzip 61.4 kB N/A -
2266-HASH.js gzip 4.69 kB N/A -
3317.HASH.js gzip 169 B N/A -
4866-HASH.js gzip 5.64 kB N/A -
9e302639-HASH.js gzip 62.8 kB N/A -
framework-HASH.js gzip 59.5 kB 59.5 kB
main-app-HASH.js gzip 254 B 254 B
main-HASH.js gzip 39.9 kB 39.9 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
175fd0fd-HASH.js gzip N/A 62.8 kB -
2596-HASH.js gzip N/A 5.63 kB -
34-HASH.js gzip N/A 61.3 kB -
5691.HASH.js gzip N/A 169 B -
9156-HASH.js gzip N/A 4.68 kB -
Total 236 kB 236 kB ✅ -99 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 193 B 193 B
_error-HASH.js gzip 181 B 182 B
css-HASH.js gzip 334 B 332 B
dynamic-HASH.js gzip 1.79 kB 1.81 kB
edge-ssr-HASH.js gzip 255 B 255 B
head-HASH.js gzip 351 B 348 B
hooks-HASH.js gzip 385 B 384 B
image-HASH.js gzip 580 B 580 B
index-HASH.js gzip 257 B 259 B
link-HASH.js gzip 2.51 kB 2.52 kB
routerDirect..HASH.js gzip 318 B 319 B
script-HASH.js gzip 387 B 386 B
withRouter-HASH.js gzip 316 B 316 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.97 kB 7.99 kB ⚠️ +19 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 126 kB 126 kB
page.js gzip 276 kB 270 kB 🟢 5.3 kB (-2%)
Total 402 kB 396 kB ✅ -5.52 kB
Middleware
Canary PR Change
middleware-b..fest.js gzip 619 B 616 B
middleware-r..fest.js gzip 155 B 155 B
middleware.js gzip 44.4 kB 44.8 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 46 kB 46.4 kB ⚠️ +364 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 719 B 717 B
Total 719 B 717 B ✅ -2 B
Build Cache
Canary PR Change
0.pack gzip 4.49 MB 4.48 MB 🟢 5.61 kB (0%)
index.pack gzip 115 kB 114 kB 🟢 1.2 kB (-1%)
index.pack.old gzip 116 kB 114 kB 🟢 1.73 kB (-1%)
Total 4.72 MB 4.71 MB ✅ -8.54 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 350 kB 350 kB
app-page-exp..prod.js gzip 195 kB 195 kB
app-page-tur...dev.js gzip 350 kB 350 kB
app-page-tur..prod.js gzip 194 kB 194 kB
app-page-tur...dev.js gzip 346 kB 346 kB
app-page-tur..prod.js gzip 192 kB 192 kB
app-page.run...dev.js gzip 347 kB 347 kB
app-page.run..prod.js gzip 193 kB 193 kB
app-route-ex...dev.js gzip 77.5 kB 77.5 kB
app-route-ex..prod.js gzip 52.9 kB 52.9 kB
app-route-tu...dev.js gzip 77.6 kB 77.6 kB
app-route-tu..prod.js gzip 52.9 kB 52.9 kB
app-route-tu...dev.js gzip 77.2 kB 77.2 kB
app-route-tu..prod.js gzip 52.7 kB 52.7 kB
app-route.ru...dev.js gzip 77.1 kB 77.1 kB
app-route.ru..prod.js gzip 52.7 kB 52.7 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 44.3 kB 44.3 kB
pages-api-tu..prod.js gzip 33.8 kB 33.8 kB
pages-api.ru...dev.js gzip 44.3 kB 44.3 kB
pages-api.ru..prod.js gzip 33.7 kB 33.7 kB
pages-turbo....dev.js gzip 53.7 kB 53.7 kB
pages-turbo...prod.js gzip 39.4 kB 39.4 kB
pages.runtim...dev.js gzip 53.6 kB 53.6 kB
pages.runtim..prod.js gzip 39.4 kB 39.4 kB
server.runti..prod.js gzip 63.1 kB 63.1 kB
use-cache-pr...dev.js gzip 69.7 kB 69.7 kB
use-cache-pr...dev.js gzip 69.7 kB 69.7 kB
use-cache-pr...dev.js gzip 68 kB 68 kB
use-cache-pr...dev.js gzip 68 kB 68 kB
Total 3.37 MB 3.37 MB
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/e1343eba4ff88b1d47e3bbeb7079fcaf49ed11a7/next

Commit: e1343eb

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants