Skip to content

Commit 76a9ecb

Browse files
Reflexcursoragent
andcommitted
test: prove H2 bulkheads on the wire; lock sync lazy init
Add TLS+ALPN integration tests that saturate waits / stall upload bodies and assert create lands on a different connection and stays fast. Guard sync bulkhead client creation with a lock and enumerate long-lived resource paths so new endpoints cannot silently join the API pool. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent bb09391 commit 76a9ecb

3 files changed

Lines changed: 515 additions & 18 deletions

File tree

src/runloop_api_client/_base_client.py

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,7 @@ def __init__(
10731073
self._closed = False
10741074
self._background_clients = {}
10751075
self._transfer_clients = {}
1076+
self._bulkhead_lock = threading.Lock()
10761077
self._background_pool_shards = background_pool_shards
10771078
self._transfer_pool_shards = transfer_pool_shards
10781079
# Custom http_client owns the full transport stack; don't invent sibling pools.
@@ -1118,29 +1119,37 @@ def _ensure_background_client(self, shard: int) -> httpx.Client:
11181119
existing = self._background_clients.get(shard)
11191120
if existing is not None:
11201121
return existing
1121-
if self._uses_shared_pool:
1122-
transport: httpx.BaseTransport | None = _acquire_shared_sync_transport(
1123-
_shared_sync_background_transports, shard
1124-
)
1125-
else:
1126-
transport = None
1127-
client = self._make_bulkhead_client(transport=transport)
1128-
self._background_clients[shard] = client
1129-
return client
1122+
with self._bulkhead_lock:
1123+
existing = self._background_clients.get(shard)
1124+
if existing is not None:
1125+
return existing
1126+
if self._uses_shared_pool:
1127+
transport: httpx.BaseTransport | None = _acquire_shared_sync_transport(
1128+
_shared_sync_background_transports, shard
1129+
)
1130+
else:
1131+
transport = None
1132+
client = self._make_bulkhead_client(transport=transport)
1133+
self._background_clients[shard] = client
1134+
return client
11301135

11311136
def _ensure_transfer_client(self, shard: int) -> httpx.Client:
11321137
existing = self._transfer_clients.get(shard)
11331138
if existing is not None:
11341139
return existing
1135-
if self._uses_shared_pool:
1136-
transport: httpx.BaseTransport | None = _acquire_shared_sync_transport(
1137-
_shared_sync_transfer_transports, shard
1138-
)
1139-
else:
1140-
transport = None
1141-
client = self._make_bulkhead_client(transport=transport)
1142-
self._transfer_clients[shard] = client
1143-
return client
1140+
with self._bulkhead_lock:
1141+
existing = self._transfer_clients.get(shard)
1142+
if existing is not None:
1143+
return existing
1144+
if self._uses_shared_pool:
1145+
transport: httpx.BaseTransport | None = _acquire_shared_sync_transport(
1146+
_shared_sync_transfer_transports, shard
1147+
)
1148+
else:
1149+
transport = None
1150+
client = self._make_bulkhead_client(transport=transport)
1151+
self._transfer_clients[shard] = client
1152+
return client
11441153

11451154
def _send_client_for_request(self, request: httpx.Request) -> httpx.Client:
11461155
if not self._isolate_workload_pools:

0 commit comments

Comments
 (0)