Commit e272eee
authored
feat: async Python client for non-blocking sandbox operations (#510)
* feat: add async Python sandbox client
Add AsyncSandboxClient and supporting async modules so users can
await sandbox creation, command execution, and file I/O without
blocking the event loop. This is needed for async frameworks like
FastAPI, aiohttp, and async agent orchestrators.
Key design decisions:
- Explicit retry logic matching sync client's status-code retries
- asyncio.Lock guards on shared state for coroutine safety
- BaseException handling to catch CancelledError during create
- try/finally on all K8s watch streams to prevent leaked connections
- Required connection_config (no LocalTunnel support in async)
- Lazy __getattr__ import with actionable ImportError message
Optional deps: pip install k8s-agent-sandbox[async]
Supersedes #256.
* fix: clear sandbox registry on close, set httpx default timeout
- Clear _active_connection_sandboxes after closing connections to
prevent stale references
- Set httpx.AsyncClient timeout to 60s matching sync client behavior
(httpx defaults to 5s)
Made-with: Cursor
* remove internal plan doc from PR
Made-with: Cursor
* fix: address code review feedback
- Remove dead retry branch in async connector (retryable status codes
are handled before raise_for_status, so the except handler never
sees them)
- Narrow except BaseException to except (Exception, CancelledError)
to avoid catching KeyboardInterrupt/SystemExit
- Replace logging.basicConfig() with logging.getLogger(__name__) so
library code doesn't hijack the root logger
- Use built-in generics (list, dict, tuple) instead of typing imports
since project requires Python 3.10+
- Replace __getattr__ lazy import with global try/except pattern
- Add test for close() clearing the sandbox registry
Made-with: Cursor
* fix: address second round of review feedback
- Make fallback AsyncSandboxClient a class so isinstance() works
- Use logger = logging.getLogger(__name__) in async_connector and
async_k8s_helper (was still using root logger)
- Add None event guard to resolve_sandbox_name watch loop to prevent
TypeError crash on None events
- Document no-atexit behavior in AsyncSandboxClient docstring
Made-with: Cursor
* fix: add transport-level retries for connection errors
Add AsyncHTTPTransport(retries=3) so connection-level failures (TCP,
DNS) are retried at the transport layer, matching the sync client's
urllib3.Retry behavior. The manual retry loop handles status-code
retries (500/502/503/504) which the transport doesn't cover.
Made-with: Cursor
* fix: retry watch streams on premature connection drops
Watch streams can close prematurely due to network blips or API server
restarts, causing an erroneous TimeoutError even when only seconds have
elapsed. Track a deadline and re-establish the watch with remaining time
instead of raising immediately.
Fixed in all 6 watch methods (3 sync + 3 async): resolve_sandbox_name,
wait_for_sandbox_ready, wait_for_gateway_ip.
Made-with: Cursor1 parent 4eceb03 commit e272eee
13 files changed
Lines changed: 1589 additions & 81 deletions
File tree
- clients/python/agentic-sandbox-client
- k8s_agent_sandbox
- commands
- files
- test/unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
189 | 189 | | |
190 | 190 | | |
191 | 191 | | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
192 | 226 | | |
193 | 227 | | |
194 | 228 | | |
| |||
Lines changed: 12 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
Lines changed: 141 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
0 commit comments