Skip to main content

Bedrock-fallback-engine

AWS-native resilience for Amazon Bedrock. Cross-region, cross-model failover with schema validation and per-route CloudWatch telemetry.

CI PyPI version Python versions Docker MCP License: MIT

Watch us-east-1 fail. Watch the request still succeed. ↓

Live failover demo

Same endpoint. Same response. Different region. Every failover is a CloudWatch metric.

🎙️ Use with Alexa+ (via MCP)

This repository ships a Model Context Protocol (MCP) server that Alexa+ skills can invoke as a tool. When a user asks Alexa+ a complex query, the skill calls this MCP server — which routes the request across Bedrock models and regions, ensuring zero downtime if the primary model throttles or a region fails.

Why it matters for Alexa+: voice interactions cannot tolerate "please try again later." When us-east-1 throttles, an Alexa+ skill that calls Bedrock directly fails the request. With bedrock-fallback-engine, the request silently fails over to us-west-2 — the user never hears the interruption.

MCP tools exposed

Tool What it does
bedrock_resilient_call Bedrock call with automatic cross-region/model failover
list_bedrock_routes Inspect the current route chain
get_fallback_stats Session stats: attempts, failovers, token usage
health_check Verify AWS credentials are configured

Example Alexa+ → MCP interaction

User: "Alexa, plan my week"
  │
  ▼
Alexa+ skill → MCP tool: bedrock_resilient_call(
    prompt="Plan a productive week for a software engineer...",
    max_retries=2
  )
  │
  ▼
bedrock-fallback-engine
  │
  ├─ Route 1: us-east-1 Claude 3.5 Sonnet → THROTTLED (429)
  ├─ Route 2: us-west-2 Claude 3.5 Sonnet → 200 OK ✅
  │
  ▼
Alexa+ responds: "Here's your week..."
(User never notices the failover.)

Install the MCP server

pip install "bedrock-fallback-engine[mcp]"

Add to Claude Desktop config (or any MCP client):

{
  "mcpServers": {
    "bedrock-fallback-engine": {
      "command": "uvx",
      "args": ["--from", "bedrock-fallback-engine[mcp]", "bedrock-fallback-engine-mcp"],
      "env": {
        "AWS_ACCESS_KEY_ID": "AKIA...",
        "AWS_SECRET_ACCESS_KEY": "...",
        "AWS_DEFAULT_REGION": "us-east-1"
      }
    }
  }
}

Architecture

flowchart LR
    A[Request] --> B[Engine.invoke]
    B --> C{Route 1<br/>primary}
    C -->|fail| D{Route 2<br/>cross-region}
    D -->|fail| E{Route 3<br/>cross-region profile}
    E -->|fail| F{Route 4<br/>Nova}
    F -->|fail| G{Route 5<br/>Titan}
    C -->|ok| Z[Result]
    D -->|ok| Z
    E -->|ok| Z
    F -->|ok| Z
    G -->|ok| Z
    G -->|fail| Y[RouteExhausted]
    Z --> M[CloudWatch]
    Y --> M

    style C fill:#3ad082,color:#000
    style D fill:#48a8ec,color:#000
    style E fill:#48a8ec,color:#000
    style F fill:#48a8ec,color:#000
    style G fill:#e89632,color:#000
    style Y fill:#e84e4e,color:#000
    style M fill:#9457d4,color:#000

The problem

Amazon Bedrock throttles. A region goes down. A model hits quota. When that happens mid-agent-workflow, your entire pipeline dies.

bedrock-fallback-engine wraps the Converse API in a route chain:

  • Cross-region failover — us-east-1 throttled? Try us-west-2.
  • Cross-model failover — Claude down? Try Nova.
  • Cross-provider failover — Bedrock-native models all sick? Try Llama.
  • Schema validation — malformed JSON fails over to the next route instead of crashing.
  • Token accounting — every invocation reports input/output tokens and which route served it.

Install

pip install bedrock-fallback-engine

Or with Docker for the demo:

docker build -t bedrock-demo -f demo/Dockerfile .
docker run -p 8000:8000 bedrock-demo

Requires AWS credentials configured (aws configure, env vars, or IAM role) for real Bedrock calls. The demo runs without credentials in dry-run mode.

Deploy to AWS Lambda

The library ships a small CLI that builds a Lambda-ready deployment zip:

pip install bedrock-fallback-engine

# Build a minimal zip (assumes Lambda's Python 3.12 runtime provides boto3)
bedrock-fallback-engine package

# → ✅ Wrote dist/lambda_layer.zip
#    Size: 1.24 MB

# Deploy it
aws lambda update-function-code \
  --function-name my-triage-fn \
  --zip-file fileb://dist/lambda_layer.zip

Options:

Flag Default Meaning
--output / -o dist/lambda_layer.zip Output path
--include-boto3 off Bundle boto3 (Lambda's runtime already provides it)
--verbose / -v off Debug-level logging

If your Lambda uses a custom runtime without boto3, pass --include-boto3 to bundle it.


## Quickstart

```python
from pydantic import BaseModel
from bedrock_fallback_engine import BedrockFallbackEngine

class Triage(BaseModel):
    category: str
    urgency: str

engine = BedrockFallbackEngine(schema=Triage)

result = engine.invoke([
    {"role": "user", "content": [{"text": "Classify: dashboard won't load."}]}
])

print(result.value)          # {"category": "bug", "urgency": "high"}
print(result.route.label)    # "primary"
print(result.input_tokens)   # 42
print(result.output_tokens)  # 11

If the primary region or model fails, the next route runs automatically. If every route fails, you get a BedrockRouteExhausted with the full error trail — each entry tagged with the route label that produced it.


Default routes

us-east-1 Claude 3.5 Sonnet → us-west-2 Claude 3.5 Sonnet → us-east-1 Nova Pro → us-west-2 Llama 3 70B

Bring your own:

from bedrock_fallback_engine import BedrockRoute, BedrockFallbackEngine

engine = BedrockFallbackEngine(routes=[
    BedrockRoute("eu-west-1", "anthropic.claude-3-5-sonnet-20241022-v2:0"),
    BedrockRoute("eu-central-1", "amazon.nova-pro-v1:0"),
])

Live failover demo

The demo/ folder contains a FastAPI app that demonstrates cross-region failover in real time. It runs without AWS credentials — the chaos client returns canned responses so you can try it locally in 30 seconds.

Run it locally

pip install -e .
pip install -r demo/requirements.txt

BEDROCK_DEMO_DRY_RUN=1 uvicorn demo.app:app --reload

Leave that terminal running. Then, in a second terminal, either:

  • Interactive playground: open http://localhost:8000/docs in your browser (FastAPI auto-generates Swagger UI), or
  • Direct curl calls: use the examples below.

Happy path — served by primary

curl -i -X POST http://localhost:8000/triage \
  -H 'content-type: application/json' \
  -d '{"text": "My dashboard is broken"}' | grep X-Route
X-Route-Served-By: primary
X-Route-Region: us-east-1

Failover path — served by backup

Add ?simulate_throttle=true to force the primary route to fail:

curl -i -X POST 'http://localhost:8000/triage?simulate_throttle=true' \
  -H 'content-type: application/json' \
  -d '{"text": "My dashboard is broken"}' | grep X-Route
X-Route-Served-By: cross-region
X-Route-Region: us-west-2

Same response body. Same status code. User never knew.

Response headers

Every invocation returns the routing decision as headers — perfect for demos, debugging, and dashboards:

Header Meaning
X-Route-Served-By Which route label answered
X-Route-Region AWS region that answered
X-Route-Model Bedrock model that answered
X-Input-Tokens Prompt tokens consumed
X-Output-Tokens Response tokens generated
X-Latency-Ms Route call latency in milliseconds
X-Attempts Total attempts before success

Endpoints

Method Path Purpose
GET /health Service health + route list
POST /triage Classify a ticket (with automatic failover)
GET /chaos/status Which routes are currently forced to fail
POST /chaos/clear Reset the chaos set

Run with real Bedrock

export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_DEFAULT_REGION=us-east-1
unset BEDROCK_DEMO_DRY_RUN

uvicorn demo.app:app --reload

Run with Docker

docker build -t bedrock-demo -f demo/Dockerfile .
docker run -p 8000:8000 bedrock-demo

Full demo docs: demo/README.md

## CloudWatch telemetry

Pass a `CloudWatchMetricsEmitter` to get structured metrics on every invocation.

```python
from bedrock_fallback_engine import (
    BedrockFallbackEngine,
    CloudWatchMetricsEmitter,
)

metrics = CloudWatchMetricsEmitter(namespace="MyApp/Bedrock", flush_size=20)
engine = BedrockFallbackEngine(schema=Triage, metrics=metrics)

engine.invoke([...])  # metrics emitted automatically

Metrics emitted:

Metric Unit Dimensions
InvocationCount Count RouteLabel, Region, ModelId, Status
InvocationLatency Milliseconds RouteLabel, Region, ModelId
ThrottleCount Count RouteLabel, Region, ModelId
TransientErrorCount Count RouteLabel, Region, ModelId
FallbackTriggered Count FromRoute, ToRoute
RouteExhausted Count —
InputTokens Count RouteLabel, Region, ModelId
OutputTokens Count RouteLabel, Region, ModelId

Telemetry is best-effort — if CloudWatch is unreachable, the engine keeps working. Buffer auto-flushes at flush_size points. Call metrics.flush() explicitly at shutdown to drain the buffer.

Example CloudWatch Insights query

fields @timestamp, RouteLabel, FromRoute, ToRoute
| filter MetricName = "FallbackTriggered"
| sort @timestamp desc


AWS-native emergency fallback

The default route chain includes two AWS-native resilience tiers:

  1. Cross-region inference profile — us.anthropic.claude-3-5-sonnet-20241022-v2:0. Bedrock auto-routes this across any US region with capacity. Platform-level resilience.
  2. Emergency Titan route — amazon.titan-text-premier-v1:0. Amazon's own model. Rarely throttled, always available.

No local AI. No external service. Pure Bedrock → Bedrock → Bedrock failover.


Design principles

  1. Zero surprises. Route order is explicit; failover is deterministic.
  2. Dependency-light. Only boto3 and pydantic at runtime.
  3. Two loops, clearly separated. Retries happen within a route; failover happens between routes.
  4. Testable. Inject a fake client factory; no AWS calls in the test suite.
  5. Observable. Every route attempt, retry, failure, and success emits an event you can hook into CloudWatch, Prometheus, or a logger.

How retries vs. failover work

Route 1 (us-east-1, Claude)
 ├─ attempt 1  fail
 ├─ attempt 2  fail  (retry within route)
 └─ attempt 3  fail  → give up on route

Route 2 (us-west-2, Claude)
 └─ attempt 1  success  ← returned

Retries (max_retries) apply inside each route. Failover is between routes. When a route can't be saved, the engine doesn't retry it forever — it moves on.


Roadmap

  • Cross-region / cross-model failover
  • Schema validation with failover
  • Structured error trail
  • Token usage per invocation
  • CloudWatch metrics emission
  • Local emergency fallback (Ollama)
  • Lambda deployment packaging

License

MIT — see LICENSE.

Metadata

Release files for bedrock-fallback-engine 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bedrock-fallback-engine 0.3.0
File Size Uploaded Provenance Actions
bedrock_fallback_engine-0.3.0.tar.gz 28.4 kB With provenance Details for bedrock_fallback_engine-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for bedrock-fallback-engine 0.3.0
File Interpreter ABI Platform Actions
bedrock_fallback_engine-0.3.0-py3-none-any.whl Python 3 none any Details for bedrock_fallback_engine-0.3.0-py3-none-any.whl

Total release size: 51.8 kB

Release files / bedrock_fallback_engine-0.3.0.tar.gz

Download URL bedrock_fallback_engine-0.3.0.tar.gz
Size 28.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8830e191a1744a91ff537d10a8e85e1669d09bcccd9faf4215732d95063b2d83
BLAKE2b-256 checksum
How to use checksums
6e393d2b278f657407e60756ab527a766b6a90b8b90be96b6c90d6a8c30567d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Release files / bedrock_fallback_engine-0.3.0-py3-none-any.whl

Download URL bedrock_fallback_engine-0.3.0-py3-none-any.whl
Size 23.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6bee99e1bc5bfec1393eddc8df6339ab536f3154158de93bf221aaa13974121c
BLAKE2b-256 checksum
How to use checksums
089b061fff667ae3e31e7d3ed8710c10dbb2742b85234d1a566556b0bf247752
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Security for bedrock-fallback-engine 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for bedrock_fallback_engine-0.3.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page