Skip to content
AI.info

Recommender systems

Production Architecture, Freshness, Monitoring, and Incidents

Design production recommendation architecture with online and nearline data, feature serving, caching, freshness, observability, fallbacks, and incident response.

By the end you can

Example

12 June 2025: the service answered, and the answer was wrong

On 12 June 2025 Cloudflare's Workers KV went down, and every service that depends on it went with it. Cloudflare's post-mortem gives the size of the hole: “This outage lasted 2 hours and 28 minutes, and globally impacted all Cloudflare customers using the affected services.” Nothing in Cloudflare's own ranking, routing or policy code had failed first. The trigger was an outage at a third-party cloud provider.

The other half of the day belongs to Google Cloud, upstream. A quota-policy feature had been added to Service Control on 29 May 2025. Google's incident report is blunt about it: “The issue with this change was that it did not have appropriate error handling nor was it feature flag protected.” On 12 June, blank fields replicated globally within seconds. A null pointer put the binaries into a crash loop worldwide. Recovery in us-central1 took about 2 hours 40 minutes.

This is the shape a recommendation incident actually takes. Read the five findings below against a serving path — ranker, vector index, feature service, eligibility cache, fallback policy. Every one of them transfers.

  • Component health: The code that failed was not the code anyone was watching. Cloudflare's own services were running. The dependency beneath them was not. Google's report puts the defect in a Service Control quota-policy path that had shipped fourteen days earlier, with no error handling and no feature flag to hold it back.
  • Data freshness: Binary and policy data aged apart. The change went out on 29 May 2025. The blank fields that detonated it replicated globally within seconds on 12 June 2025. A deployment date says nothing about when the data that exercises that deployment will arrive.
  • Dependency failure: Degradation propagated by design. Cloudflare's report notes that “when unavailable, Gateway is designed to fail closed to prevent traffic from bypassing customer-configured rules”. That is the correct choice for a security product. It was also an outage for everyone behind it the moment Workers KV went away.
  • Fallback quality: The emergency policy kept the service answering. It also broke a guarantee the normal path enforced. From the post-mortem: “Notably, while these kill switches were active, Turnstile’s siteverify API (the API that validates issued tokens) could redeem valid tokens multiple times, potentially allowing for attacks where a bad actor might try to use a previously valid token to bypass.” The fallback was available. It was not equivalent.
  • Trace gap: Reconstructing the day took two documents from two companies. Cloudflare's post-mortem said what its users saw; Google's incident report said why. No single trace inside either system spanned the failure. A recommendation stack with candidates, features, scores, rules and a final slate has more seams than that, not fewer.

Comparison

Netflix published the tiering, and the latency number that forces it

The online/nearline/batch split is not a teaching device invented for a course. It is how Netflix says its own stack is built. Amatriain and Basilico set the three tiers out in a 2015 handbook chapter, in a section titled “Offline, Nearline, and Online Computation”. Real-time there means a response below a few hundred milliseconds. The example SLA is concrete: recommendations returned in 250 ms for 99% of requests.

That number is what makes the fallback structural rather than a nicety. The chapter says so directly: “Also, a purely online computation may fail to meet its SLA in some circumstances, so it is always important to have a fast fallback mechanism such as reverting to a precomputed result.” The precomputed result exists because the online path is allowed to run out of time.

Freshness and cost then trade along the row. The online path computes request-specific state at serving time: lowest staleness, highest latency sensitivity, strict fallbacks, and the natural home for session and inventory context. The nearline path refreshes embeddings, counters or candidates every few minutes. It balances freshness against cost, and it has to survive events arriving out of order, so its updates have to be idempotent. It carries trends and recent behaviour. The batch tier — what the chapter calls offline computation — rebuilds large aggregates, models and indexes periodically. Efficient, reproducible, able to absorb heavy processing, home to durable profiles and full rebuilds. Stale by design.

FigureComparison · 3 columns

Online path

Computes request-specific state at serving time.

  • Lowest staleness
  • Highest latency sensitivity
  • Needs strict fallbacks
  • Useful for session and inventory context

Nearline path

Updates embeddings, counters, or candidates every few minutes.

  • Balances freshness and cost
  • Complex event-time handling
  • Needs idempotent updates
  • Useful for trends and recent behavior

Batch path

Builds large aggregates, models, and indexes periodically.

  • Efficient and reproducible
  • Can be stale
  • Supports heavy processing
  • Useful for durable profiles and full rebuilds

Case

Amazon in 2003, Netflix in 2015, both in print

Both companies have described their production stacks in print. Amazon published item-to-item collaborative filtering in January 2003. Netflix's account came in 2015, from Gomez-Uribe and Hunt. They improve the system, they wrote, by “combining A/B testing focused on improving member retention and medium term engagement, as well as offline experimentation using historical member engagement data”.

Two loops, running at different speeds, inside one company's account of one system. Freshness tiers exist because that is the normal condition of a production recommender, not an accident of one architecture.

The model is the small black box in the middle

The ML code is the small black box in the middle of the picture. A 2015 paper on hidden technical debt in machine learning systems, by ten authors at Google, drew it that way and captioned it: “Only a small fraction of real-world ML systems is composed of the ML code, as shown by the small black box in the middle. The required surrounding infrastructure is vast and complex.” The serving path around that box may include request context, identity, eligibility, user state, candidate services, vector indexes, feature stores, rankers, re-rankers, policy rules, caches, experiments and logging. Reliability is the reliability of all of it together.

The same paper names why component-local health does not compose. Under entanglement it gives the rule a name: “We refer to this here as the CACE principle: Changing Anything Changes Everything.” The scope is broad: inputs, hyper-parameters, learning settings, sampling methods, convergence thresholds, data selection. Change one and the rest move.

Freshness inherits that entanglement. Catalog, inventory, price, rights, user history, embeddings, graph, features, model, index and policy each age at their own rate. One “last updated” timestamp cannot speak for all of them.

Each component in that path can look healthy on its own while the slate they produce together is stale, and no single timestamp will tell you which one aged out.

Steps

There is a published rubric, and it is scored on the weakest section

Production readiness has a published rubric with numbers on it. Breck and four colleagues at Google wrote it down in 2017 and called it the ML Test Score: 28 specific tests and monitoring needs, across four sections. A test run manually scores half a point; automated, a full point. Then the arithmetic bites: “The final ML Test Score is computed by taking the minimum of the scores aggregated for each of the 4 sections.” You do not average your way out of an untested section. The rubric was calibrated in the field — “We met with 36 teams from across Google” — and it reads a score of 0 as “More of a research project than a productionized system”. Only a score above 5 counts as “Exceptional levels of automated testing and monitoring”.

Run the five operating steps against that rubric. First, define end-to-end SLOs: valid slate rate alongside latency, freshness, coverage and guardrails. Second, version the asset graph — model, feature, index, rules, catalog, creative and experiment — so a rollback can name exact versions. Third, test degraded modes deliberately: source loss, stale data, empty candidates, feature timeouts. Fourth, monitor policy behaviour: source mix, score distributions, exposure, constraints and outcomes. Fifth, prepare rollback and replay: traces, exact versions, working fallbacks, named incident decision rights.

Two of the rubric's monitoring tests are the ones this lesson keeps returning to. Monitor 1 is “Dependency changes result in notification”. The reason given is exactly the failure mode of a shared feature service: “Partial outages, version upgrades, and other changes in the source system can radically change the feature’s meaning and thus confuse the model’s training or inference, without necessarily producing values that are strange enough to trigger other monitoring.” Monitor 4 is “Models are not too stale”. Neither is satisfied by a green dashboard.

FigureProcess · 5 steps
  1. 1. Define end-to-end SLOs

    Include valid slate rate, latency, freshness, coverage, and guardrails.

  2. 2. Version the asset graph

    Track model, feature, index, rules, catalog, creative, and experiment.

  3. 3. Test degraded modes

    Exercise source loss, stale data, empty candidates, and feature timeouts.

  4. 4. Monitor policy behavior

    Track source mix, score distributions, exposure, constraints, and outcomes.

  5. 5. Prepare rollback and replay

    Preserve traces, exact versions, fallbacks, and incident decision rights.

Example

Split-brain cost $460 million in 45 minutes, and nothing errored

Two of the five patterns below have a documented instance attached — a regulator's findings in one case, a vendor's own root-cause report in the other. Both are worth reading before assuming that a serious version disagreement will announce itself.

  • Freshness split-brain: Seven servers held one version of reality. One held another. The SEC's 2013 order against Knight Capital records the mechanism: “During the deployment of the new code, however, one of Knight’s technicians did not copy the new code to one of the eight SMARS computer servers. Knight did not have a second technician review this deployment and no one at Knight realized that the Power Peg code had not been removed from the eighth server, nor the new RLP code added.” On 1 August 2012 that disagreement sent millions of child orders: 4 million executions in 154 stocks, over 397 million shares, about 45 minutes. It cost Knight over $460 million. The penalty was $12 million. No written procedure had required a second reviewer. The hidden-technical-debt paper cites the same incident independently: “A famous example of the dangers here was Knight Capital's system losing $465 million in 45 minutes, apparently because of unexpected behavior from obsolete experimental codepaths”.
  • Candidate-source outage: A missing source narrows coverage without triggering a visible error. This is Monitor 1 territory: a partial outage upstream changes what a feature means without producing values strange enough to trip anything else. That is why source mix belongs in the policy-behaviour step, not on the availability dashboard.
  • Fallback recursion: Retries and degraded services call one another, and the recovery becomes the load. Google's report on 12 June 2025 documents the mechanism precisely: “Within some of our larger regions, such as us-central-1, as Service Control tasks restarted, it created a herd effect on the underlying infrastructure it depends on (i.e. that Spanner table), overloading the infrastructure. Service Control did not have the appropriate randomized exponential backoff implemented to avoid this.” Recovery in us-central1 took about 2 hours 40 minutes. Not because the fix was unknown, but because everything tried to recover at once.
  • Experiment collision: Overlapping flags produce a policy combination nobody tested. The inverse failure is on record too. Google's report says of the 29 May 2025 quota-policy change that “The issue with this change was that it did not have appropriate error handling nor was it feature flag protected.” A flag you never set is a rollback you never have.
  • Silent exposure corruption: Logging loses positions or candidate provenance while serving continues. Nothing in the Knight deployment raised an error either. The eighth server answered every order it was given, correctly by its own lights, for 45 minutes. A path that keeps returning well-formed responses will not be flagged by anything that only asks whether responses came back.

Visual

A production recommendation request

One request, five things that have to happen inside the latency budget. The budget in the Netflix chapter's example SLA is 250 ms for 99% of requests. Resolve request and identity: surface, session, profile, experiment, privacy mode. Fetch eligibility and context: inventory, policy, rights, current request features. Query candidate services: collaborative, content, graph, trend, exploration. Rank and apply policy: score, constrain, diversify, lay out, and select the fallback behaviour for the moment the budget runs out.

The fifth is not for the user at all. Unless inputs, versions, candidates, scores, slate, exposure and outcomes are traced, nobody can reconstruct tomorrow why this page looked the way it did. Reconstructing 12 June 2025 took two companies and two separate reports.

FigureHierarchy · 5 levels
  • Request and identity

    Resolve surface, session, profile, experiment, and privacy mode.

    • Eligibility and context

      Fetch inventory, policy, rights, and current request features.

      • Candidate services

        Query collaborative, content, graph, trend, and exploration sources.

        • Ranking and policy

          Score, constrain, diversify, lay out, and select fallback behavior.

          • Trace and feedback

            Log inputs, versions, candidates, scores, slate, exposure, and outcomes.

Key idea

A live endpoint can still return a stale decision

A model endpoint can be available while the recommendation decision is stale, incomplete, invalid, or impossible to explain. Knight's eighth server was available. Turnstile's siteverify API was available while it redeemed the same valid token more than once. Availability is a property of the answer arriving. No threshold on a latency dashboard expresses “this answer is current”. That is why the rubric makes staleness a test of its own — Monitor 4, “Models are not too stale” — instead of trusting uptime to imply it.

Green dashboards certify that the service answered, not that the answer was current, complete, or explainable — availability metrics never report that kind of failure.

Key idea

The production gate: 21 fields, 20 values, 8.5 million machines

Release only when the team can monitor and roll back the complete policy, not merely the model binary. CrowdStrike made the case for that gate itself, in its root-cause analysis of 6 August 2024. The defect was an arity mismatch between a template and the code that called it: “The new IPC Template Type defined 21 input parameter fields, but the integration code that invoked the Content Interpreter with Channel File 291's Template Instances supplied only 20 input values to match against.” The content update of 19 July 2024 was the first to use the 21st field. The result was an out-of-bounds read and a system crash. Microsoft put the reach at 8.5 million machines: “We currently estimate that CrowdStrike's update affected 8.5 million Windows devices, or less than one percent of all Windows machines.”

The binary was not what shipped that day. A content asset was — an artefact travelling outside the release process built for code. Finding 6 of the analysis is the matching remedy: “Staged deployment mitigates impact if a new Template Instance causes failures such as system crashes, false-positive detection volume spikes or performance issues. New Template Instances that have passed canary testing are to be successively promoted to wider deployment rings or rolled back if problems are detected.” Rules, indexes, feature definitions and experiment flags are the same class of object. They are policy that reaches users without passing through the thing you know how to revert.

Shipping a model you can roll back inside a policy you cannot is a release with no exit.

Key takeaways