Skip to content

simplify session dependent tasks and add TTL support#91729

Merged
lukesandberg merged 11 commits into
canaryfrom
eviction_because_ram_is_too_expensive
Mar 31, 2026
Merged

simplify session dependent tasks and add TTL support#91729
lukesandberg merged 11 commits into
canaryfrom
eviction_because_ram_is_too_expensive

Conversation

@lukesandberg
Copy link
Copy Markdown
Contributor

@lukesandberg lukesandberg commented Mar 20, 2026

Summary

Three related improvements to turbo-tasks session-dependent task handling:

1. Make session_dependent a function attribute

Previously, tasks called mark_session_dependent() at runtime to flag themselves. This PR makes it a compile-time #[turbo_tasks::function(session_dependent)] attribute instead. Benefits:

  • Enables eager aggregation number selection: Session-dependent tasks change on every session restore, behaving like dirty leaf nodes. By knowing at task creation time (not mid-execution) that a task is session-dependent, the backend can assign a high initial aggregation number, preventing long dirty-propagation chains through intermediate aggregated nodes.
  • Simpler API: No runtime mark_session_dependent() call needed — the attribute is declarative and statically checked.
  • Removes mark_session_dependent(), mark_own_task_as_session_dependent(), and the session_dependent field from InProgressStateInner. The backend now reads is_session_dependent directly from the NativeFunction metadata via TaskGuard::is_session_dependent().

2. Fix fetch to respect HTTP Cache-Control headers

Previously, fetch results were cached indefinitely meaning results would never be refreshed (unless the cache was invalidated). Now they are session_dependent with a TTL to ensure we respect the http settings (e.g. Google Fonts with max-age=86400).

New two-task pattern:

  • fetch_inner ( NOT session_dependent): Performs the HTTP request, grabs an Invalidator for itself, and returns the response + invalidator + absolute deadline. Cached across sessions.
  • fetch (network, session_dependent): Reads the cached fetch_inner result and spawns a timer to invalidate when the TTL expires.

On warm cache restore, fetch re-executes (session-dependent), reads the persisted deadline from fetch_inner's cached result, computes remaining TTL, and spawns a timer — no HTTP request unless the TTL has already expired. Mid-session, the timer fires and triggers a re-fetch.

Error handling: On fetch failure, fetch_inner takes a dependency on Completion::session_dependent() so transient errors (network down, DNS failure) are retried on the next session without busy-looping.

3. Drop TransientState in favor of inline solution

TransientState was only used in one place (EcmascriptModuleAsset::last_successful_parse) and brought unnecessary complexity — it registered invalidators and called mark_session_dependent() on every read. Replaced with a simple TransientCache<T> local to turbopack-ecmascript that is just a Mutex<Option<T>> with #[bincode(skip)].

Test Plan

  • 3 new integration tests in turbo-tasks-fetch/tests/fetch.rs:
    • ttl_invalidates_within_session — mock server returns max-age=1, body changes, verifies re-fetch after TTL
    • ttl_invalidates_on_session_restore — fetches with TTL, stops TT, waits for expiry, warm restores with new TT, verifies re-fetch
    • errors_retried_on_session_restore — server returns 500, stops TT, fixes server, warm restores, verifies success
  • Existing 6 fetch tests continue to pass
  • cargo check -p turbo-tasks -p turbo-tasks-backend -p turbo-tasks-fetch

@nextjs-bot nextjs-bot added created-by: Turbopack team PRs by the Turbopack team. Turbopack Related to Turbopack with Next.js. labels Mar 20, 2026
Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@nextjs-bot
Copy link
Copy Markdown
Contributor

nextjs-bot commented Mar 20, 2026

Tests Passed

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 20, 2026

Merging this PR will degrade performance by 3.5%

❌ 1 regressed benchmark
✅ 16 untouched benchmarks
⏩ 3 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation packages-bundle.js[full] 957.3 ms 992 ms -3.5%

Comparing eviction_because_ram_is_too_expensive (d0d5a9f) with canary (bd3f947)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@nextjs-bot
Copy link
Copy Markdown
Contributor

nextjs-bot commented Mar 20, 2026

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) 455ms 456ms ▁▁▁▁▁
Cold (Ready in log) 439ms 439ms ▁▁▁▁▁
Cold (First Request) 1.098s 1.092s ▂▂▂▂▁
Warm (Listen) 457ms 457ms ▁▁▁▁▁
Warm (Ready in log) 445ms 443ms ▁▁▁▁▁
Warm (First Request) 346ms 342ms ▁▁▁▁▁
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 455ms 456ms ▁▁▁▁▁
Cold (Ready in log) 440ms 439ms ▁▁▄▁▁
Cold (First Request) 1.950s 1.952s ▁▂▅▃▂
Warm (Listen) 457ms 456ms ▁▁▁▁▁
Warm (Ready in log) 442ms 439ms ▁▁▄▁▁
Warm (First Request) 1.976s 1.968s ▁▂▅▃▃

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 3.836s 3.843s ▁▁▁▁▁
Cached Build 3.792s 3.826s ▁▁▁▁▁
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 14.569s 14.454s ▁▁▄▁▁
Cached Build 14.541s 14.601s ▁▁▄▁▁
node_modules Size 485 MB 485 MB ▁████
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
02fkg8wfh0iju.js gzip 9.19 kB N/A -
050zwt5xh_0tx.js gzip 10.4 kB N/A -
063vbvjo7u7e8.js gzip 158 B N/A -
06rvbj82bhyo0.js gzip 13 kB N/A -
07yw__3003_xm.js gzip 65.7 kB N/A -
087fzjd-gvlzv.js gzip 450 B N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0ppxcl_z43mad.js gzip 8.52 kB N/A -
0qg1lr8r20scw.js gzip 156 B N/A -
0rkattk-3kkvr.js gzip 153 B N/A -
0vqyehczw0bwp.js gzip 160 B N/A -
14pqs7eg65c56.js gzip 156 B N/A -
19oha6-znmkcv.js gzip 8.55 kB N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1yib9gzpx36gi.js gzip 155 B N/A -
208uruj4wqqpw.js gzip 70.8 kB N/A -
219prxwxgaalc.js gzip 7.61 kB N/A -
26elcgxnn9zjd.js gzip 8.52 kB N/A -
2900hudr6gvm0.js gzip 2.28 kB N/A -
29r2bzwlwm21l.js gzip 154 B N/A -
2gnz9dbfjr975.js gzip 162 B N/A -
2ihlsvbo2c9e8.js gzip 215 B 215 B
2j_kfppl-1cp3.js gzip 157 B N/A -
2lv2js3kmdeho.js gzip 8.48 kB N/A -
2nukmhdm6gyau.js gzip 157 B N/A -
2rehygrd36hqv.js gzip 8.58 kB N/A -
2srwswih0m9_h.js gzip 13.3 kB N/A -
3_s5aieplqtws.js gzip 154 B N/A -
3-p9p9mheqhzx.js gzip 8.55 kB N/A -
31030bryqpolg.js gzip 8.53 kB N/A -
31dx5nmrzzuy7.js gzip 225 B N/A -
36nd-apogbbqe.js gzip 169 B N/A -
3925v09gtu-5k.js gzip 49 kB N/A -
3fe6y50a9d--i.js gzip 156 B N/A -
3iu80eefg23ae.js gzip 9.77 kB N/A -
3k-48b78ys_vy.js gzip 10.1 kB N/A -
3m7-5rfj0avoz.js gzip 12.9 kB N/A -
3uqce_6sa526g.js gzip 8.47 kB N/A -
3yurjqk-sjs3y.js gzip 1.46 kB N/A -
40ybjx9c192n0.js gzip 13.8 kB N/A -
421vzwdt9j1b_.js gzip 5.62 kB N/A -
turbopack-08..gje6.js gzip 4.16 kB N/A -
turbopack-10..smw6.js gzip 4.16 kB N/A -
turbopack-13..bb0b.js gzip 4.16 kB N/A -
turbopack-19..1dit.js gzip 4.18 kB N/A -
turbopack-1b..if1b.js gzip 4.16 kB N/A -
turbopack-1h..9z04.js gzip 4.16 kB N/A -
turbopack-1o..izbx.js gzip 4.16 kB N/A -
turbopack-2_..9umd.js gzip 4.16 kB N/A -
turbopack-2r..gs77.js gzip 4.16 kB N/A -
turbopack-2t..-5kt.js gzip 4.16 kB N/A -
turbopack-2t..1zwv.js gzip 4.14 kB N/A -
turbopack-2z..n4r1.js gzip 4.16 kB N/A -
turbopack-31..e90w.js gzip 4.16 kB N/A -
turbopack-3u..0v3s.js gzip 4.16 kB N/A -
0-5aww5s8x_4c.js gzip N/A 154 B -
03dgzoo-qf3sm.js gzip N/A 9.19 kB -
05tx5f25dlivn.js gzip N/A 8.53 kB -
09rf4j1ro1yml.js gzip N/A 156 B -
0b3-z6-abkv8c.js gzip N/A 159 B -
0c7ez6p2qc57f.js gzip N/A 5.62 kB -
0duvj3qk5pvgn.js gzip N/A 13.8 kB -
0m-34rm9w_wpm.js gzip N/A 7.6 kB -
0qnwuk92m8i7o.js gzip N/A 10.4 kB -
0r4wrn6n0ue2m.js gzip N/A 8.55 kB -
0rp0fodtbt_6m.js gzip N/A 8.52 kB -
0sfck-km4dl1k.js gzip N/A 8.47 kB -
0x0xuhmxzwkp8.js gzip N/A 8.47 kB -
0x93vydqfqy0v.js gzip N/A 154 B -
1-wdvgxnzicj7.js gzip N/A 1.46 kB -
10yjsdcxz7ich.js gzip N/A 155 B -
11u6nxujb2eg4.js gzip N/A 450 B -
1gx49oxm0e1hg.js gzip N/A 156 B -
1h0ck-wf-2dfg.js gzip N/A 156 B -
1hl9033tlykjp.js gzip N/A 167 B -
1jv-o1_s-zmua.js gzip N/A 49 kB -
1l9j1ozyt2nfx.js gzip N/A 155 B -
2--no0nct7d-w.js gzip N/A 157 B -
2ivx6ud_hd-nk.js gzip N/A 159 B -
2k9ax08cjl2id.js gzip N/A 12.9 kB -
2lms6k76q5-6m.js gzip N/A 13.3 kB -
2ny7v7wu25arp.js gzip N/A 153 B -
2q3hz-jtbjs52.js gzip N/A 9.77 kB -
2qx4twi9i3xus.js gzip N/A 2.28 kB -
2siv8yyxqvs94.js gzip N/A 70.8 kB -
2srnqic6tvxxd.js gzip N/A 8.52 kB -
30l7m4nayp73a.js gzip N/A 8.55 kB -
38rr7d3kfutni.js gzip N/A 13 kB -
3csncbmlwa_5a.js gzip N/A 153 B -
3h_ecpiaatwgc.js gzip N/A 10.1 kB -
3ity0aahajapd.js gzip N/A 225 B -
3ue2_111r24_h.js gzip N/A 65.7 kB -
43mlw9dy_8f02.js gzip N/A 8.58 kB -
turbopack-0i..3s73.js gzip N/A 4.16 kB -
turbopack-0k..w0kv.js gzip N/A 4.14 kB -
turbopack-0u..us5r.js gzip N/A 4.16 kB -
turbopack-1_..3ul8.js gzip N/A 4.16 kB -
turbopack-1-..1qqo.js gzip N/A 4.16 kB -
turbopack-1c..z9y9.js gzip N/A 4.16 kB -
turbopack-1o..4cca.js gzip N/A 4.16 kB -
turbopack-20..werk.js gzip N/A 4.16 kB -
turbopack-2f..nzkj.js gzip N/A 4.16 kB -
turbopack-2v..r4j6.js gzip N/A 4.16 kB -
turbopack-3-..cg2d.js gzip N/A 4.16 kB -
turbopack-34..479i.js gzip N/A 4.16 kB -
turbopack-3h.._01f.js gzip N/A 4.18 kB -
turbopack-3o..mus4.js gzip N/A 4.16 kB -
Total 464 kB 464 kB ✅ -35 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 720 B 718 B
Total 720 B 718 B ✅ -2 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 434 B 431 B
Total 434 B 431 B ✅ -3 B

📦 Webpack

Client

Main Bundles
Canary PR Change
5528-HASH.js gzip 5.54 kB N/A -
6280-HASH.js gzip 60.7 kB N/A -
6335.HASH.js gzip 169 B N/A -
912-HASH.js gzip 4.59 kB N/A -
e8aec2e4-HASH.js gzip 62.8 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 256 B 254 B
main-HASH.js gzip 39.3 kB 39.2 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
262-HASH.js gzip N/A 4.59 kB -
2889.HASH.js gzip N/A 169 B -
5602-HASH.js gzip N/A 5.55 kB -
6948ada0-HASH.js gzip N/A 62.8 kB -
9544-HASH.js gzip N/A 61.4 kB -
Total 235 kB 235 kB ⚠️ +648 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 194 B 194 B
_error-HASH.js gzip 183 B 180 B 🟢 3 B (-2%)
css-HASH.js gzip 331 B 330 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 351 B 352 B
hooks-HASH.js gzip 384 B 383 B
image-HASH.js gzip 580 B 581 B
index-HASH.js gzip 260 B 260 B
link-HASH.js gzip 2.51 kB 2.51 kB
routerDirect..HASH.js gzip 320 B 319 B
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 315 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.98 kB 7.98 kB ✅ -1 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 125 kB 125 kB
page.js gzip 270 kB 270 kB
Total 396 kB 396 kB ⚠️ +145 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 617 B 614 B
middleware-r..fest.js gzip 156 B 155 B
middleware.js gzip 44.1 kB 43.8 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 45.7 kB 45.4 kB ✅ -289 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 715 B 718 B
Total 715 B 718 B ⚠️ +3 B
Build Cache
Canary PR Change
0.pack gzip 4.35 MB 4.34 MB 🟢 5.11 kB (0%)
index.pack gzip 110 kB 110 kB
index.pack.old gzip 110 kB 110 kB
Total 4.57 MB 4.57 MB ✅ -4.96 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 336 kB 336 kB
app-page-exp..prod.js gzip 186 kB 186 kB
app-page-tur...dev.js gzip 335 kB 335 kB
app-page-tur..prod.js gzip 185 kB 185 kB
app-page-tur...dev.js gzip 332 kB 332 kB
app-page-tur..prod.js gzip 183 kB 183 kB
app-page.run...dev.js gzip 332 kB 332 kB
app-page.run..prod.js gzip 184 kB 184 kB
app-route-ex...dev.js gzip 76.3 kB 76.3 kB
app-route-ex..prod.js gzip 51.9 kB 51.9 kB
app-route-tu...dev.js gzip 76.3 kB 76.3 kB
app-route-tu..prod.js gzip 51.9 kB 51.9 kB
app-route-tu...dev.js gzip 75.9 kB 75.9 kB
app-route-tu..prod.js gzip 51.7 kB 51.7 kB
app-route.ru...dev.js gzip 75.9 kB 75.9 kB
app-route.ru..prod.js gzip 51.7 kB 51.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 43.5 kB 43.5 kB
pages-api-tu..prod.js gzip 33.1 kB 33.1 kB
pages-api.ru...dev.js gzip 43.5 kB 43.5 kB
pages-api.ru..prod.js gzip 33.1 kB 33.1 kB
pages-turbo....dev.js gzip 52.9 kB 52.9 kB
pages-turbo...prod.js gzip 38.7 kB 38.7 kB
pages.runtim...dev.js gzip 52.9 kB 52.9 kB
pages.runtim..prod.js gzip 38.7 kB 38.7 kB
server.runti..prod.js gzip 62.5 kB 62.5 kB
Total 2.99 MB 2.99 MB ⚠️ +1 B
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/d0d5a9ff7705360959b790b1ac151c2a2f139e27/next

@lukesandberg lukesandberg marked this pull request as ready for review March 20, 2026 19:00
@lukesandberg lukesandberg requested a review from bgw March 20, 2026 19:00
@bgw bgw marked this pull request as draft March 20, 2026 23:38
Copy link
Copy Markdown
Member

@bgw bgw left a comment

Choose a reason for hiding this comment

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

Please update turbo-tasks/function.md with information about the new parameter

Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs
Comment thread turbopack/crates/turbopack-ecmascript/src/lib.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
Comment thread turbopack/crates/turbo-tasks-fetch/src/client.rs Outdated
@lukesandberg lukesandberg marked this pull request as ready for review March 21, 2026 02:00
@lukesandberg lukesandberg force-pushed the eviction_because_ram_is_too_expensive branch from 5d52480 to bbb97c0 Compare March 22, 2026 00:49
@lukesandberg lukesandberg force-pushed the eviction_because_ram_is_too_expensive branch 2 times, most recently from 55308e3 to 1a7464a Compare March 31, 2026 07:58
@lukesandberg lukesandberg force-pushed the eviction_because_ram_is_too_expensive branch from 1a7464a to d0d5a9f Compare March 31, 2026 17:56
@lukesandberg lukesandberg merged commit fe99f0d into canary Mar 31, 2026
402 of 415 checks passed
Copy link
Copy Markdown
Contributor Author

Merge activity

@lukesandberg lukesandberg deleted the eviction_because_ram_is_too_expensive branch March 31, 2026 23:51
lukesandberg added a commit that referenced this pull request Apr 3, 2026
lukesandberg added a commit that referenced this pull request Apr 3, 2026
#92320)

This is causing OOMs in some applications running with a persistent cache

See discussion: https://vercel.slack.com/archives/C03EWR7LGEN/p1775159630054759

The issue appears to be invalidating the chunk graph in an odd way that causes us to allocate an ~infinite number of error strings
lukesandberg added a commit that referenced this pull request Apr 3, 2026
lukesandberg added a commit that referenced this pull request Apr 7, 2026
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Apr 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

created-by: Turbopack team PRs by the Turbopack team. locked Turbopack Related to Turbopack with Next.js.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants