<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vikar Egor</title>
    <description>The latest articles on DEV Community by Vikar Egor (@vikar_egor).</description>
    <link>https://dev.to/vikar_egor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4025492%2F77901e82-6377-437f-bbb4-fe32afcbe1b2.png</url>
      <title>DEV Community: Vikar Egor</title>
      <link>https://dev.to/vikar_egor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vikar_egor"/>
    <language>en</language>
    <item>
      <title>Solana RPC Failover: Multi-Provider Redundancy Done Right</title>
      <dc:creator>Vikar Egor</dc:creator>
      <pubDate>Fri, 17 Jul 2026 16:53:18 +0000</pubDate>
      <link>https://dev.to/vikar_egor/solana-rpc-failover-multi-provider-redundancy-done-right-2np7</link>
      <guid>https://dev.to/vikar_egor/solana-rpc-failover-multi-provider-redundancy-done-right-2np7</guid>
      <description>&lt;p&gt;Most Solana teams already pay for two RPC providers. Ask them why, and the answer is "redundancy." But look at how the second provider is actually wired in and you usually find the same pattern: one provider is hardcoded as the endpoint, and the other is a URL someone will paste in when things break. That isn't redundancy. It's a backup that requires a human to activate — and the human is usually asleep when it matters.&lt;/p&gt;

&lt;p&gt;Real failover means traffic moves to a healthy provider automatically, in under a second, without anyone waking up. Getting there takes three things most setups are missing: a definition of "healthy" that goes beyond HTTP 200, a mechanism to route around unhealthy providers, and a way to bring them back safely. Here's how to think about each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual failover is a backup, not redundancy
&lt;/h2&gt;

&lt;p&gt;The problem with human-in-the-loop failover isn't that people are unreliable. It's the latency. A provider degrades at 2am. Alerts fire, someone acknowledges, logs in, confirms it's not their own bug, swaps the endpoint, redeploys, and waits for the change to propagate. That's minutes to tens of minutes of degraded or failed requests — and on a chain where a transaction has to land inside a narrow slot window, minutes is an eternity.&lt;/p&gt;

&lt;p&gt;Automated failover collapses that loop to a health check and a routing decision. The tradeoff is that you have to encode "is this provider healthy?" as a rule a machine can evaluate continuously. That turns out to be the hard and interesting part.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Is it up?" is the wrong question
&lt;/h2&gt;

&lt;p&gt;The instinct is to failover when a provider returns errors. That catches the easy case — a provider that's hard-down, returning 500s or refusing connections. But the failures that actually cost you on Solana rarely look like errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slot drift.&lt;/strong&gt; A provider is answering every request with a clean &lt;code&gt;200 OK&lt;/code&gt;, but its view of the chain is several slots behind the network tip. Your &lt;code&gt;getAccountInfo&lt;/code&gt; returns real data — just stale data. Your uptime graph stays green the whole time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commitment stalls.&lt;/strong&gt; A node's &lt;code&gt;processed&lt;/code&gt; slot keeps advancing while its &lt;code&gt;confirmed&lt;/code&gt; pipeline quietly freezes. Probe only the optimistic tip and it looks perfectly fresh, while every &lt;code&gt;confirmed&lt;/code&gt; read serves increasingly old state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limits.&lt;/strong&gt; A &lt;code&gt;429&lt;/code&gt; isn't a fault — the provider is fine, you're just over your quota on that key for the moment. You want to shed load off it &lt;em&gt;without&lt;/em&gt; declaring it down, because it'll have headroom again in seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A failover system that only reacts to hard errors misses all three. The fix is to score providers on a continuous signal, not a binary one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Health scoring: pick the &lt;em&gt;best&lt;/em&gt; provider, not just an up one
&lt;/h2&gt;

&lt;p&gt;Instead of a live/dead flag, give each provider a score in &lt;code&gt;[0, 1]&lt;/code&gt;, recomputed every probe cycle, from the signals that actually predict good responses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Latency&lt;/strong&gt; — round-trip time on a lightweight probe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error rate&lt;/strong&gt; — fraction of recent probes that failed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slot freshness&lt;/strong&gt; — how far behind the network tip the provider is, measured &lt;em&gt;per commitment&lt;/em&gt; so a stalled &lt;code&gt;confirmed&lt;/code&gt; pipeline demotes the provider even when &lt;code&gt;processed&lt;/code&gt; looks current.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recent success rate&lt;/strong&gt; — a fast-reacting signal so a provider that just started failing loses priority immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The network tip itself is just the maximum slot across your providers — which has a blind spot: if they all stall together, the tip slides down with them and drift reads as zero. An optional external reference endpoint (probed, never routed to) closes that gap. The router then always sends reads to the highest-scoring provider and uses the sorted list as its failover order. You're not just avoiding dead providers; you're continuously steering toward the freshest, fastest one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Circuit breakers: fail fast, recover safely
&lt;/h2&gt;

&lt;p&gt;Scoring decides &lt;em&gt;who's best&lt;/em&gt;. A circuit breaker decides &lt;em&gt;who's excluded&lt;/em&gt;, and — just as important — &lt;em&gt;when to trust a provider again&lt;/em&gt;. The pattern is three states:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Closed&lt;/strong&gt; — normal. All requests eligible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt; — the provider is excluded from routing. The circuit opens after N consecutive probe failures, or when the rolling error rate crosses a threshold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HalfOpen&lt;/strong&gt; — after a cooldown, one probe is allowed through. Success closes the circuit and restores the provider; failure reopens it and resets the timer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cooldown is what stops flapping. Without it, a provider that fails one request, recovers, fails again, would thrash in and out of rotation and drag your latency with it. With it, a struggling provider gets a quiet interval to recover before it's trusted with real traffic again.&lt;/p&gt;

&lt;p&gt;Two nuances matter here. &lt;strong&gt;Rate limits should not open the circuit.&lt;/strong&gt; A &lt;code&gt;429&lt;/code&gt; means fail this request over to a peer &lt;em&gt;and&lt;/em&gt; demote the provider's score so routing sheds load — but keep it eligible, because opening its circuit for a full cooldown just dumps its traffic onto everyone else at the exact moment the system is under pressure. And &lt;strong&gt;client errors shouldn't touch provider health at all&lt;/strong&gt; — a malformed request (a &lt;code&gt;400&lt;/code&gt; or &lt;code&gt;404&lt;/code&gt;) is your bug, not the provider's, and one buggy client loop shouldn't be able to serially trip every provider's breaker.&lt;/p&gt;

&lt;p&gt;One more safety valve: if &lt;em&gt;every&lt;/em&gt; provider's circuit is open, route to all of them anyway. A degraded attempt beats refusing to try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing a routing strategy
&lt;/h2&gt;

&lt;p&gt;Redundancy isn't one-size-fits-all. The right strategy depends on whether you're optimizing for reliability, cost, or raw latency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best-score&lt;/strong&gt; — every read goes to the healthiest provider right now. The sensible default for most production workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failover-ordered&lt;/strong&gt; — a strict primary → secondary hierarchy. The secondary only sees traffic when the primary's circuit opens. Ideal for a cheap-or-dedicated primary with a metered backup you don't want billed unless you need it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weighted-random&lt;/strong&gt; — spread load proportionally across providers of similar quality. This is how you stay under per-provider rate limits and split cost across keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel-race&lt;/strong&gt; — send to all healthy providers at once, return the first success. Your latency tracks the &lt;em&gt;fastest&lt;/em&gt; provider, at the cost of N× the request volume.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wiring it up
&lt;/h2&gt;

&lt;p&gt;You can build all of this yourself — background health probes, a per-provider scorer, a circuit-breaker state machine, and retry logic that knows a &lt;code&gt;429&lt;/code&gt; from a &lt;code&gt;-32005&lt;/code&gt; "node is behind." Or you can drop a proxy in front of your providers that already does it.&lt;/p&gt;

&lt;p&gt;That's what &lt;a href="https://rpcplane.dev" rel="noopener noreferrer"&gt;RPC Plane&lt;/a&gt; is: a small self-hosted binary you point your app at instead of a single provider URL. It probes each configured provider, scores them, trips circuit breakers, and routes around failures automatically — one config file, no application code changes. The &lt;a href="https://docs.rpcplane.dev/routing/" rel="noopener noreferrer"&gt;routing&lt;/a&gt; and &lt;a href="https://docs.rpcplane.dev/health-scoring/" rel="noopener noreferrer"&gt;health-scoring&lt;/a&gt; docs cover the full tuning surface.&lt;/p&gt;

&lt;p&gt;Either way, the takeaway is the same: &lt;strong&gt;two providers you fail over by hand is a backup. Two providers that a health-scored router keeps both live is redundancy.&lt;/strong&gt; The difference only shows up at 2am — which is exactly when you can't afford to be the failover mechanism yourself.&lt;/p&gt;

</description>
      <category>solana</category>
      <category>rpc</category>
      <category>jsonrpc</category>
      <category>redundancy</category>
    </item>
  </channel>
</rss>
