EXP-3418: skip init wait when the routed config version is already loaded - #489
Draft
luismeyer wants to merge 1 commit into
Draft
EXP-3418: skip init wait when the routed config version is already loaded#489luismeyer wants to merge 1 commit into
luismeyer wants to merge 1 commit into
Conversation
EXP-3418 Reads the existing `x-vercel-edge-config-versions` request context header, selects the exact `flags_<projectId>` entry derived from the loaded definitions, and resolves `initialize()` right away when the local `configUpdatedAt` is at or ahead of that version, while the stream or poll keeps updating in the background. No config id and no new header are involved. A missing request context, project or entry, a malformed/unsafe version, a duplicated entry, and local data without a usable `configUpdatedAt` all preserve the previous behavior of waiting up to `initTimeoutMs`. The controller stays in `initializing:*` until the source actually connects, so no connection is reported before it exists, and the existing `configUpdatedAt` guard still keeps background updates from replacing newer definitions with equal or older ones. The low cardinality outcome is attached to `FLAGS_CONFIG_READ` events as `configRoutedInit` and never carries ids or header values. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-Authored-By: Luis Meyer <luis.meyer@vercel.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
luismeyer
marked this pull request as draft
September 2, 2026 13:33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
EXP-3418
@vercel/flags-corewaits for a stream confirmation or a first poll on every cold start, even when the definitions it already has in hand are current. Vercel already tells us which config version a request was routed to, so that wait is avoidable.What changed
src/utils/edge-config-versions.tsparses the existingx-vercel-edge-config-versionsrequest header, a semicolon-separated map of store name to version (flags_prj_123=1758000000000;ecfg_abc=1757000000000). It selects only the exactflags_<projectId>entry — no prefix, suffix or substring matching — and accepts only non-negative safe integers.src/controller/routed-init.tsreads the header from the existing Vercel request context (utils/request-context.ts), derives the key from theprojectIdof the loaded data, and compares the localconfigUpdatedAtagainst the routed version.initialize()returns immediately when localconfigUpdatedAt >= routed version, while the stream (or poll + interval) keeps updating in the background.No config id is involved and no new header is requested — only the header that is already on the request context.
Preserved behavior
All of these keep waiting up to
initTimeoutMsexactly as before:projectIdon the loaded dataNaN/Infinity, beyondNumber.MAX_SAFE_INTEGERconfigUpdatedAtTwo more invariants are covered by tests:
initializing:*after an immediate init, so reads reportconnectionState: 'disconnected'andmode: 'offline'until the source emitsconnected.configUpdatedAtguard still applies to the background stream/poll updates.Metrics
FLAGS_CONFIG_READevents carry a newconfigRoutedInitfield — one ofimmediate,behind,invalid,duplicate,unknown-local. It is a fixed low-cardinality enum, carries no project ids or header values, and is omitted entirely when no routed version applied, so existing event payloads are unchanged.Tests
src/utils/edge-config-versions.test.ts— 18 focused parser tests (exact match, whitespace, duplicates, malformed/unsafe versions)src/controller/routed-init.test.ts— 31 focused decision tests (missing context/project/match, comparison, unsafe values on both sides)src/black-box.test.ts— 23 tests through the public API: immediate init for provided datafile, equal version, bundled definitions and polling mode; the full preserve-behavior table; connection reporting; the equal/older guard; and the metric assertions including a negative check that no ids or header values are ingestedRepo-wide
pnpm type-check(18/18) andpnpm test(17/17) also pass.Notes
cacheStatusstaysSTALEduring the immediate-init window because it is derived from the connection state, matching the existing timeout-fallback and polling-with-data paths. Changing that is a separate metrics decision.src/index.make.test.tsin a way its own comment forbids; that change was reverted and is not part of this PR.🤖 Generated with Claude Code