Skip to content

Reduce EID KV write conflicts during page loads #993

Description

@ChristianPavilonis

Description

Trusted Server saves IDs from the ts-eids and sharedId cookies while finishing every returning-user response. A normal publisher page creates many first-party requests at once, including scripts, integration requests, analytics calls, and auctions. Each response may try to update the same EC record in KV.

A matched production browser run recorded 45 warnings for one EC identity:

CAS conflict after 5 retries upserting 3 partner IDs

The page continued because this sync is best-effort, but some partner IDs may not have been saved.

Relevant code:

  • crates/trusted-server-core/src/ec/finalize.rs
  • crates/trusted-server-core/src/ec/prebid_eids.rs
  • crates/trusted-server-core/src/ec/kv.rs
  • crates/trusted-server-adapter-fastly/src/app.rs
  • crates/trusted-server-adapter-fastly/src/main.rs

Current behavior

For every returning-user response:

  1. Read partner IDs from the request cookies.
  2. Read the EC record and its generation number from KV.
  3. Merge the partner IDs.
  4. Write only if the generation number has not changed.
  5. Retry immediately up to five times when another request writes first.

Requests may contain cookies captured at different points during the page load. They can also finish in a different order from the one in which they started.

CAS prevents two requests from writing the same version of the record. It does not tell Trusted Server which request has the newest cookie values. An older request can reread the record and try to replace a newer partner ID with an older value.

Impact

  • Some partner IDs may not be saved.
  • Older cookie values may replace newer values.
  • Page loads create unnecessary KV reads and writes.
  • Immediate retries use edge compute while the record remains busy.
  • Repeated warnings make Fastly logs harder to read.
  • Later auctions and partner syncs may use an incomplete identity record.

The browser request still succeeds, so this problem is easy to miss without Fastly logs.

Proposed solution

Limit where partner IDs are saved

Keep consent checks, withdrawal handling, and EC cookie handling on every response where they are currently required. Limit only the partner ID sync.

Save EID cookie values during:

  • New EC creation
  • Top-level document navigation
  • POST /auction

Do not save them while serving static assets, integration requests, analytics calls, or other page resources.

If navigation and auction requests miss IDs discovered late in the page load, add a dedicated browser sync endpoint instead of saving IDs on every response.

Replace repeated writes with one conflict check

Replace the five immediate write retries with:

  1. Read the record and attempt one conditional write.
  2. If another request writes first, read the record one more time.
  3. Return success if the desired IDs are already present.
  4. Otherwise defer the update to a later navigation or auction request.

Do not make another immediate write from the same request after the conflict.

Prevent older values from replacing newer ones

Before allowing one partner ID value to replace another, define a clear rule for deciding which value is newer. This may require storing the time when Trusted Server observed each partner ID.

Until that rule exists, a request that loses a CAS conflict should not overwrite a different value found during the follow-up read.

Add measurements

Add counters for:

  • Partner ID sync attempts
  • Requests where the values already matched
  • Successful KV writes
  • Conflicts where another request had already saved the same values
  • Updates deferred after a conflict
  • Whether the sync came from navigation, auction, or new EC creation

Logs and measurements must not contain EC IDs or partner ID values.

Completion criteria

  • Static files and integration requests do not write partner IDs to KV.
  • New EC creation, document navigation, and /auction still save partner IDs.
  • A conflict returns success when another request already saved the same values.
  • An older request cannot replace a newer partner ID after losing a conflict.
  • Consent withdrawal continues to take priority on every applicable route.
  • Concurrent request tests no longer exhaust five immediate retries.
  • Measurements distinguish successful, duplicate, and deferred updates without exposing identity data.

Out of scope

  • Increasing the retry limit
  • Sleeping inside an edge request
  • Logging EC IDs or partner ID values
  • Changing consent withdrawal behavior

Metadata

Metadata

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions