Beyond the Pager: How Stripe Uses Graph Search and State Machines for Automated DB Remediation
For any Site Reliability Engineer (SRE), the 3 AM page is a rite of passage. In the early days of a startup, these alerts are often straightforward: a disk is full, a process crashed, or a network link flapped. You log in, run a pre-written script or a manual command, and go back to sleep. However, as infrastructure scales to the level of a global financial engine like Stripe, the nature of these “incidents” shifts from isolated failures to complex, multi-component puzzles.
Stripe’s persistence layer, primarily built on MongoDB, manages massive amounts of critical financial data. At this scale, the traditional approach to remediation—writing a specific plugin or script for every known failure mode—reaches a breaking point. This is known as the “Combinatorial Explosion” problem. When you have dozens of interdependent components (shards, config servers, routers, and storage nodes), the number of ways they can fail together grows exponentially. You cannot possibly write, test, and maintain a script for every permutation of “Node A is down while Node B is undergoing a maintenance task and the Config Server is partitioned.”
This fragility led Stripe to rethink the fundamental way they approach self-healing infrastructure. Instead of treating remediation as a series of “If-This-Then-That” (IFTTT) workflows, they moved toward a declarative, graph-based model. By representing their entire database fleet as a dynamic graph and using pathfinding algorithms like Dijkstra’s, Stripe has built a system that doesn’t just follow a script—it “reasons” its way back to health.
The 3 AM Bottleneck: Why Hard-Coded Remediation Fails at Scale
In a traditional SRE environment, remediation logic is often imperative. An automation platform detects an alert and triggers a specific “remediation plugin.” For example, if a MongoDB secondary node lags too far behind the primary, a plugin might trigger a resync command.
This works well for isolated, simple issues. But consider a scenario where a network partition occurs. Suddenly, five different alerts fire. Five different plugins might attempt to run simultaneously. One might try to restart a service, while another tries to re-provision a node, and a third tries to change the replica set configuration. Without a centralized understanding of the system’s state, these imperative scripts can conflict, potentially worsening the outage or leading to data inconsistency.
Furthermore, the maintenance overhead of imperative scripts is staggering. Every time a new version of a database is deployed or a new architectural component is added, every single relevant remediation script must be audited and updated. At Stripe’s scale, this “script rot” becomes a significant liability. The challenge wasn’t just fixing the database; it was managing the complexity of the fixes themselves. They needed a system that could handle partial failures and find the “least bad” path forward when a perfect recovery wasn’t immediately possible.
From Scripts to Schemas: Modeling Infrastructure as a Graph
The core innovation in Stripe’s new approach is the shift from imperative logic to a declarative graph model. In this framework, the entire database infrastructure is treated as a collection of Nodes and Edges within a control plane.
Representing Components as Nodes
In the graph, every physical or logical component of the MongoDB ecosystem is a node. This includes:
- Physical Nodes: The actual EC2 instances or bare-metal servers.
- Logical Processes: Individual
mongodormongosinstances. - Clusters/Shards: Groupings of processes that form a functional unit.
- Config Servers: The metadata providers for the cluster.
Defining Edges as Relationships
The edges in the graph define the relationships and dependencies between these nodes. These aren’t just network connections; they are logical constraints. For example:
is-member-of: A process node belongs to a specific shard node.replicates-from: A secondary node points to a primary node.runs-on: A logical process is hosted on a specific physical instance.
Capturing Real-Time State
Each node in the graph carries dynamic attributes that represent its current state. Is the process running? Is the disk at 90% capacity? Is the node currently in “STARTUP2” state?
By modeling infrastructure this way, the system creates a “Digital Twin” of the fleet. When a failure occurs, the graph reflects the broken state. The remediation task then becomes a mathematical problem: how do we transition the current “Broken Graph” back to a “Healthy Graph”?
This approach aligns closely with modern security practices. When automating infrastructure changes, understanding the full dependency graph is crucial for security threat modeling, ensuring that automated actions don’t inadvertently open security holes or violate compliance boundaries.
Pathfinding for Health: Applying Dijkstra’s Algorithm to Infrastructure
Once the infrastructure is modeled as a graph, Stripe uses a Planner to identify the best course of action. This is where the system moves beyond simple scripts and into the realm of graph search.
The Planner treats the “Healthy State” as a destination in a graph traversal problem. However, in a complex system, there isn’t just one way to get from Point A (Broken) to Point B (Healthy). There might be several possible sequences of actions.
To choose the best one, Stripe employs Dijkstra’s Algorithm. Traditionally used in network routing or GPS navigation to find the shortest path between two points, Dijkstra’s is used here to find the “lowest cost” recovery path.
The Concept of “Cost” in Remediation
In this context, “cost” is a heuristic assigned to different remediation actions. For example:
- Restarting a process: Low cost (fast, low risk).
- Re-provisioning a whole node: Medium cost (takes time, involves data transfer).
- Triggering a database election: High cost (causes a brief period of write unavailability).
- Restoring from a backup: Very high cost (slow, potential data loss).
The Planner evaluates all valid transitions and calculates the total cost of each path. By selecting the path with the lowest cumulative cost, the system ensures it always chooses the least disruptive action that achieves the goal.
Handling the Impossible: The “Least Misconfigured State”
One of the most powerful features of this graph-based approach is its ability to handle “impossible” recoveries. In a massive multi-component failure, it might be impossible to reach a 100% healthy state immediately (e.g., if a whole AWS Availability Zone is down).
A traditional script would simply fail and page a human. Stripe’s system, however, searches for the Least Misconfigured State. If it can’t reach “Healthy,” it looks for the state that is “closest” to healthy. It might perform partial remediation—fixing three out of five broken components—which reduces the blast radius and simplifies the eventual manual intervention.
# Conceptual example of a Planner's cost evaluation
def calculate_remediation_path(current_state, target_state):
# graph represents the state space of the infrastructure
path = dijkstra.find_shortest_path(
graph,
start=current_state,
end=target_state,
weight_func=lambda action: action.cost
)
if not path:
# If the target is unreachable, find the "closest" possible state
return find_least_misconfigured_state(current_state)
return path
Composable Rules and State Machines
To make the graph search effective, the transitions between states must be strictly defined. Stripe uses State Machines governed by Composable Rules.
Instead of a monolithic workflow, the system uses small, modular rules that define how a single component can transition from one state to another. For instance, a rule might state: “If a node is in ‘Down’ state and the underlying instance is ‘Healthy’, the valid transition is ‘Start Process’.”
Declarative over Imperative
In an imperative system, you tell the computer how to fix the problem: ssh into node; run systemctl start mongodb. In Stripe’s declarative system, you define what a “Started” state looks like and provide a rule that knows how to move a “Stopped” node to “Started.”
This modularity allows for high levels of reuse. A rule written to handle a disk-full error on a MongoDB shard can often be reused for a config server, because the underlying state transition (clearing logs or expanding a volume) is the same.
Ensuring Idempotency and Safety
Because the system is based on state machines, every action is inherently idempotent. If the Planner decides to “Start Process” and the command is sent but the network flaps, the next time the Planner runs, it will see the state is still “Stopped” and simply issue the command again. There’s no risk of running a “half-finished” script that leaves the system in an inconsistent state.
This level of rigor is essential when dealing with automated systems that could potentially be targeted by malicious actors. As we’ve seen in other domains, like AI recommendation poisoning, automated systems that lack strict state validation can be manipulated. Stripe’s state machine approach ensures that the system only moves between pre-defined, valid infrastructure states.
Comparison: Imperative vs. Declarative Remediation
To understand the shift, it’s helpful to compare the two paradigms side-by-side:
| Feature | Imperative (Legacy Plugins) | Declarative (Graph + State Machines) |
|---|---|---|
| Logic Structure | Hard-coded “If-This-Then-That” | Composable rules and graph traversal |
| Scalability | Poor; scripts grow with complexity | High; rules are modular and reusable |
| Conflict Handling | Difficult; scripts may fight each other | Centralized; Planner sees the whole graph |
| Edge Cases | Must be manually programmed | Discovered via graph search |
| Maintenance | High; scripts rot over time | Low; model updates reflect infra changes |
| Failure Response | Binary (Success or Page Human) | Nuanced (Partial remediation/Least Misconfigured) |
Quantifying the Impact: 200 Fewer Pager Alerts Per Year
The transition to graph-based remediation wasn’t just a theoretical exercise; it produced measurable improvements in Stripe’s operational health.
Reducing Pager Fatigue
The most significant metric was a 30% reduction in total database-related pager alerts. For the SRE teams, this translated to roughly 200 fewer pages per year. In the world of high-stakes finance, where an alert often requires immediate, high-stress intervention, saving 200 alerts is a massive win for engineer well-being and retention.
Automating Complex Maintenance
Beyond reactive healing, the system also automated complex, multi-step maintenance tasks. One prime example is automated index builds. In MongoDB, building an index on a large collection can be resource-intensive and requires careful coordination across the replica set to avoid performance degradation.
Stripe’s system treats an index build as a state transition. The Planner coordinates the build across secondaries first, manages the rotation, and finally handles the primary, all while monitoring the health of the graph to ensure no other failures are occurring. This has reduced the time shards spend in “unhealthy” or “degraded” states by approximately 12 days per year.
The Human Factor
By automating the “toil”—the repetitive, tactical work of keeping the database running—Stripe has allowed its SREs to focus on high-leverage architectural work. Instead of fixing the same shard for the tenth time, engineers are now building the next generation of financial primitives.
Future Horizons: From Reactive Healing to Proactive Orchestration
Stripe’s journey with graph-based remediation is far from over. The success of the MongoDB control plane has provided a blueprint for other areas of their infrastructure.
Topology and Blue-Green Deployments
The next step is extending the graph framework to handle planned topology changes. Imagine a system where you don’t write a deployment script, but instead simply update the “Target Graph” to include a new region or a new shard. The Planner would then calculate the optimal series of steps to move the global fleet from the current topology to the new one, handling all the intermediate migrations and health checks automatically.
Proactive Orchestration
Currently, the system is largely reactive—it responds to a deviation from the healthy state. The future lies in proactive orchestration, where the system identifies trends (like a steady increase in disk latency) and initiates “pre-emptive remediation” before an alert ever fires.
The Convergence with AI
As infrastructure grows even more complex, the integration of AI and machine learning with these graph-based models is inevitable. While Stripe’s current system relies on deterministic Dijkstra’s search, future iterations might use machine learning to better calculate the “cost” of actions based on historical performance data, or to suggest new “rules” that a human might have missed.
By moving beyond the pager and embracing the mathematical elegance of graph search and state machines, Stripe has demonstrated that even the most complex global systems can be made self-healing. For the rest of the industry, the message is clear: the era of the imperative script is ending; the era of the intelligent control plane has begun.