Skip to content
AutoSuggesAutoSugges home
Start free
Menu
Appearance
Appearance: System.

Blog

The cache can never come before the meter

· AKHBaig

Why the order is absolute

Every request into the AutoSugges edge Worker goes through five stages in a fixed order: resolve the key, authorize the origin and token, meter and check quota, consult the cache, then read KV. Two of these reorderings look like harmless optimizations in a diff and are not.

  • A cache ahead of authorization serves one tenant’s data to whoever holds a warm key — the cache does not know who is asking, and by the time it answers nobody has checked.
  • A cache ahead of metering undercounts exactly the cheapest traffic to send: the requests that cost least to serve become the ones that bill nothing, which at volume is the same as having no meter.

Enforced by the type system, not a code review

The ordering is not a convention documented for reviewers to catch — it is structural. ResolvedRequest, AuthorizedRequest and MeterClearance are classes with private constructors and private fields. TypeScript ties a private member’s identity to its declaring class, so no object literal and no structurally identical declaration can satisfy those types from outside the module that produces them.

The function that reads an artifact from cache or KV takes a MeterClearance. The only way to produce one requires an AuthorizedRequest, which in turn requires a ResolvedRequest. A pipeline that tries to consult the cache before metering, or metering before authorization, simply does not compile — there is no legal way to construct the value the next stage demands.

What happens on exhaustion

The quota-exhausted branch lives inside the gated function itself, not in the code that calls it, so no caller can accidentally skip it. An exhausted clearance reaches neither the cache nor KV, and the response it returns is a structured quota_exceeded body with no real data and no synthetic items standing in for real ones — marked non-cacheable, so an intermediary cannot keep serving it after quota resets or a plan upgrades.

Rejections never meter, either: a CORS preflight and a mismatched origin both return or throw before any code path to the meter exists, rather than behind a flag that could be flipped later.