next.js
fe99f0d6 - simplify session dependent tasks and add TTL support (#91729)

Commit
4 days ago
simplify session dependent tasks and add TTL support (#91729) ## 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`
Author
Parents
Loading