> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Provider Fallback with ExecutionPlan

> Declarative provider fallback strategies using Effect.ts ExecutionPlan

Effect 3.16+ introduces `ExecutionPlan` for declarative retry/fallback strategies across different providers. This is ideal for production systems needing high availability.

<Note>
  Requires Effect 3.16.0 or later. Check your version with `pnpm list effect`.
</Note>

## Basic Setup

```typescript theme={null}
import { ExecutionPlan, Schedule, Layer, Effect } from "effect"
import { 
  Provider, 
  HttpTransport, 
  getBalance 
} from "voltaire-effect"

// Define fallback chain with different providers
const ProviderPlan = ExecutionPlan.make(
  {
    // Primary: Infura with 2 retries, 1 second apart
    provide: Layer.provide(Provider, HttpTransport(process.env.INFURA_URL!)),
    attempts: 2,
    schedule: Schedule.spaced("1 second")
  },
  {
    // Secondary: Alchemy with 3 retries, exponential backoff
    provide: Layer.provide(Provider, HttpTransport(process.env.ALCHEMY_URL!)),
    attempts: 3,
    schedule: Schedule.exponential("500 millis")
  },
  {
    // Fallback: Public RPC (single attempt)
    provide: Layer.provide(Provider, HttpTransport("https://eth.llamarpc.com"))
  }
)

// Apply to any effect requiring ProviderService
const robust = getBalance("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").pipe(
  Effect.withExecutionPlan(ProviderPlan)
)

await Effect.runPromise(robust)
```

## How It Works

1. **First provider fails** → Retries according to its schedule (up to `attempts` times)
2. **All retries exhausted** → Moves to next provider in the chain
3. **Success at any point** → Returns result, skips remaining providers
4. **All providers fail** → Returns error from final provider

## Advanced Schedules

Combine Effect Schedule primitives for sophisticated retry logic:

```typescript theme={null}
import { Schedule } from "effect"

const ProviderPlan = ExecutionPlan.make(
  {
    provide: Layer.provide(Provider, HttpTransport(process.env.PRIMARY_RPC!)),
    attempts: 5,
    schedule: Schedule.exponential("200 millis").pipe(
      Schedule.jittered,                    // Add randomness to prevent thundering herd
      Schedule.either(Schedule.spaced("5 seconds"))  // Cap at 5s max
    )
  },
  {
    provide: Layer.provide(Provider, HttpTransport(process.env.BACKUP_RPC!)),
    // No attempts = single try, but schedule allows retries
    schedule: Schedule.recurs(2)  // 2 retries
  }
)
```

## Multiple Operations

Apply the same plan to multiple operations:

```typescript theme={null}
import { Effect } from "effect"
import { getBalance, getBlockNumber, getTransactionCount } from "voltaire-effect"

const address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"

const robustOperations = Effect.all({
  balance: getBalance(address),
  blockNumber: getBlockNumber(),
  nonce: getTransactionCount(address)
}).pipe(
  Effect.withExecutionPlan(ProviderPlan)
)
```

## Benefits

| Feature         | Description                                        |
| --------------- | -------------------------------------------------- |
| **Declarative** | Define retry/fallback logic once, apply anywhere   |
| **Composable**  | Combine with Effect schedules for complex patterns |
| **Type-safe**   | Full TypeScript inference for layers and errors    |
| **Observable**  | Works with Effect tracing and logging              |

## Comparison with FallbackTransport

`FallbackTransport` is transport-level, `ExecutionPlan` is effect-level:

```typescript theme={null}
// Transport-level: switches on any transport error
import { FallbackTransport } from "voltaire-effect"

const transport = FallbackTransport([
  HttpTransport(process.env.PRIMARY_RPC!),
  HttpTransport(process.env.BACKUP_RPC!)
])

// Effect-level: more control, works with any layer
const plan = ExecutionPlan.make(
  { provide: Layer.provide(Provider, HttpTransport(url1)), attempts: 3 },
  { provide: Layer.provide(Provider, HttpTransport(url2)) }
)
```

Use `ExecutionPlan` when you need:

* Different retry strategies per provider
* Fine-grained schedule control
* Fallback for non-transport layers (signers, formatters, etc.)

## Next Steps

* [HttpTransport](/integrations/effect-ts) - Transport configuration
* [Effect Schedule](https://effect.website/docs/scheduling) - Schedule combinators
* [Effect 3.16 Release](https://effect.website/blog/releases/effect/316/) - ExecutionPlan announcement
