Multi-Region Client Strategy
A single SDK client only ever talks to one region. To work across regions, you build one client per region and route requests to the right one.
Busque em todas as páginas da documentação
A single SDK client only ever talks to one region. To work across regions, you build one client per region and route requests to the right one.
This page shows a small, reusable pattern: a per-region client cache, latency-based selection, and failover for disaster recovery.
The core idea is a factory that returns a cached client for a given region.
Build a client the first time a region is requested, store it, and hand back the same instance afterward. This keeps construction cheap and connection pools warm.
# --- Python (boto3) ---
import boto3
_clients = {}
def s3_for(region: str):
# Reuse a cached client per region instead of rebuilding it.
if region not in _clients:
_clients[region] = boto3.client("s3", region_name=region)
return _clients[region]
# Route by choosing the region.
us = s3_for("us-east-1")
eu = s3_for("eu-west-1")// --- TypeScript (AWS SDK v3) ---
import { S3Client } from "@aws-sdk/client-s3";
const clients = new Map<string, S3Client>();
function s3For(region: string): S3Client {
// Reuse a cached client per region instead of rebuilding it.
let c = clients.get(region);
if (!c) {
c = new S3Client({ region });
clients.set(region, c);
}
return c;
}
// Route by choosing the region.
const us = s3For("us-east-1");
const eu = s3For("eu-west-1");Routing is now just choosing a region string. The endpoint follows from the region automatically.
Here is latency-aware selection: read from the region nearest the caller, with an explicit list of candidates.
The caller supplies a preferred region; the factory returns the matching client, and the same object is reused on every subsequent request for that region.
# --- Python (boto3) ---
import boto3
REGIONS = ["us-east-1", "eu-west-1", "ap-southeast-1"]
_ddb = {}
def ddb_for(region: str):
if region not in REGIONS:
raise ValueError(f"Unsupported region: {region}")
if region not in _ddb:
_ddb[region] = boto3.client("dynamodb", region_name=region)
return _ddb[region]
def read_item(region: str, table: str, key: dict):
client = ddb_for(region)
return client.get_item(TableName=table, Key=key).get("Item")
item = read_item("eu-west-1", "Sessions", {"id": {"S": "sess-42"}})
print(item)// --- TypeScript (AWS SDK v3) ---
import { DynamoDBClient, GetItemCommand } from "@aws-sdk/client-dynamodb";
const REGIONS = ["us-east-1", "eu-west-1", "ap-southeast-1"];
const ddb = new Map<string, DynamoDBClient>();
function ddbFor(region: string): DynamoDBClient {
if (!REGIONS.includes(region)) throw new Error(`Unsupported region: ${region}`);
let c = ddb.get(region);
if (!c) { c = new DynamoDBClient({ region }); ddb.set(region, c); }
return c;
}
async function readItem(region: string, table: string, key: Record<string, unknown>) {
const client = ddbFor(region);
const out = await client.send(new GetItemCommand({ TableName: table, Key: key as never }));
return out.Item;
}
const item = await readItem("eu-west-1", "Sessions", { id: { S: "sess-42" } });
console.log(item);The function body never mentions endpoints. Selecting the region is the whole routing decision.
Each client resolves its own endpoint from its region at construction. A us-east-1 client resolves dynamodb.us-east-1.amazonaws.com; an eu-west-1 client resolves the Ireland host. Routing between them is just holding references to both.
The cache matters because construction sets up a connection pool. Rebuilding a client per request discards that pool and adds latency and CPU for nothing.
For read-local workloads, pick the region geographically closest to the caller. On compute inside AWS, that is usually the region the code runs in, available from the environment or instance metadata.
Latency routing is a client-side choice; DNS-based options like Route 53 latency records handle it at the network layer instead.
For DR, keep a primary and a secondary region. Try the primary, and on a regional failure (throttling that will not clear, connectivity errors, or a service-health event) fail over to the secondary.
Failover only works if the data exists in both regions, which means DynamoDB global tables, S3 cross-region replication, or an equivalent.
# --- Python (boto3) ---
from botocore.exceptions import ClientError, EndpointConnectionError
def read_with_failover(table, key, primary="us-east-1", secondary="us-west-2"):
for region in (primary, secondary):
try:
return ddb_for(region).get_item(TableName=table, Key=key).get("Item")
except (EndpointConnectionError, ClientError):
continue # try the next region
raise RuntimeError("All regions failed")// --- TypeScript (AWS SDK v3) ---
async function readWithFailover(
table: string, key: Record<string, unknown>,
primary = "us-east-1", secondary = "us-west-2",
) {
for (const region of [primary, secondary]) {
try {
const out = await ddbFor(region).send(
new GetItemCommand({ TableName: table, Key: key as never }),
);
return out.Item;
} catch { /* try the next region */ }
}
throw new Error("All regions failed");
}Cross-region data transfer is billed. Reading from a distant region on every request can quietly raise your bill, so route to the nearest region and reserve cross-region calls for failover.
arn:aws: when routing across partitions.Client-side routing is simplest when one application owns the logic; network-layer options scale better across many clients.
A client resolves and binds its endpoint from a single region at construction. To reach another region you need another client bound to it.
Yes. Client construction sets up connection pools, so cache one client per region and reuse it rather than rebuilding per request.
On AWS compute, use the region the code runs in (from the environment or instance metadata). Otherwise map the caller's location to a candidate region.
You do not set endpoints at all. Each region's client resolved its own endpoint, so choosing the client chooses the endpoint.
The data must exist in both regions. Use global tables, cross-region replication, or a similar mechanism so the secondary can serve the same reads.
It is simpler for a single application. Route 53 latency or failover routing scales better when many clients need the same behavior.
Cross-region data transfer. Reading from a distant region on every request adds transfer charges, so keep normal traffic in-region.
No. Availability varies and newer services arrive in some regions later, so confirm a service exists in a region before routing there.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última atualização: 23 de jul. de 2026