Repository navigation
EN SDK Clusters and Bulk
English · Türkçe · Languages / Diller
Scope: JSON API Forge 0.5.1 · Source review: 17 September 2026 · Language: English
A cluster client selects among endpoints of the same logical service. It does not replicate servers, synchronize databases or move application state across regions. Safe failover depends on equivalent contracts and consistent deployment data.
import os
from json_api_forge import ForgeCluster, ForgeEndpoint, RoutingStrategy, CircuitBreakerPolicy
endpoints = [
ForgeEndpoint("region-a", "https://a.example.com", api_key=os.environ["REGION_A_KEY"]),
ForgeEndpoint("region-b", "https://b.example.com", api_key=os.environ["REGION_B_KEY"]),
]
with ForgeCluster(
endpoints,
strategy=RoutingStrategy.RENDEZVOUS,
circuit_breaker=CircuitBreakerPolicy(failure_threshold=3, recovery_seconds=15),
) as cluster:
response = cluster.request(
"GET", "api/wiki-demo/v1/items",
routing_key="tenant-42", params={"limit": 20},
)ROUND_ROBIN is the default. RENDEZVOUS creates a stable ordering from the routing key and endpoint name; weight influences the score. Endpoint names must be unique. Adding/removing endpoints and circuit state can change selection. A routing key is not tenant authorization.
Transport errors and HTTP >=500 are retryable cluster failures. This differs from the application client's RetryPolicy status list; do not assume 429 triggers identical client retries and cluster failover.
A circuit opens after the configured consecutive-failure threshold. After recovery time, an endpoint becomes eligible again. If all circuits are open, the code can select the oldest-open endpoint as a probe, so it does not guarantee that no requests will be sent.
GET/HEAD/OPTIONS/PUT/DELETE are method-eligible for failover; other methods require idempotency_key. One request ID is preserved across endpoint attempts. Adding client-level RetryPolicy can multiply the overall attempts and timeout budget.
For side-effecting failover, targets must see the same logical business and idempotency state. Two regions with independent databases can process the same key independently. The SDK does not create a distributed transaction.
ForgeCluster.bulk_create(project, resource, payloads, max_workers=8, max_items=10000, ...) returns a separate result for each input. Results retain input order as BulkResult(index, value, error) objects. succeeded indicates whether the error is empty. Worker count is capped at 64; the configurable input ceiling is 100000.
This is not one database transaction. For partial failures, consider only failed items and their safe idempotency contract; do not blindly resend the entire list.
async def run_jobs(cluster, commands):
jobs = [
lambda command=command: cluster.call_operation(
"wiki-demo", "items.rename", command["payload"],
idempotency_key=command["key"],
)
for command in commands
]
return await cluster.bulk(jobs, concurrency=8, max_items=500)AsyncForgeCluster.bulk accepts callables that produce awaitables. lambda command=command captures the intended loop item rather than the final value. Default concurrency is 16, capped at 256. Synchronous bulk_create and async bulk do not have identical interfaces.
health_all returns a response or exception for each endpoint; it does not start background monitoring. Closing the cluster closes its owned clients. See the complete cluster signatures.
This page describes the behavior at the pinned commits below. Recheck these contracts when upgrading.