|
| 1 | +Bulkhead & Rate-Limit Headers |
| 2 | +============================= |
| 3 | + |
| 4 | +``resilience`` recovers from failures and ``rate_limit`` paces calls, but |
| 5 | +nothing capped the number of *simultaneous* in-flight calls to one resource |
| 6 | +(so a slow dependency could exhaust every worker), and the HTTP client read |
| 7 | +``Retry-After`` / ``RateLimit-*`` response headers but honored none of them. |
| 8 | +This adds a bulkhead (bounded-concurrency permit with load-shedding) and a |
| 9 | +parser for the server's advised delay. |
| 10 | + |
| 11 | +Pure standard library (``threading`` + ``email.utils``); the permit counting is |
| 12 | +non-blocking (reject when full), so it is deterministic and CI-testable without |
| 13 | +spawning threads. Imports no ``PySide6``. |
| 14 | + |
| 15 | +Headless API |
| 16 | +------------ |
| 17 | + |
| 18 | +.. code-block:: python |
| 19 | +
|
| 20 | + from je_auto_control import Bulkhead, BulkheadFullError, next_delay |
| 21 | +
|
| 22 | + payments = Bulkhead(max_concurrent=4, name="payments") |
| 23 | + try: |
| 24 | + result = payments.run(call_payment_api, order) |
| 25 | + except BulkheadFullError: |
| 26 | + defer(order) # shed load instead of piling on |
| 27 | +
|
| 28 | + # honor the server's back-off after an HTTP call |
| 29 | + wait = next_delay(response) # from Retry-After / RateLimit-* headers |
| 30 | + if wait: |
| 31 | + sleep(wait) |
| 32 | +
|
| 33 | +``Bulkhead`` caps simultaneous holders to ``max_concurrent`` — ``try_enter`` / |
| 34 | +``release``, a context manager, and ``run(func)`` all reject (``BulkheadFullError``) |
| 35 | +when full, isolating one slow dependency from exhausting the rest. |
| 36 | +``parse_retry_after`` understands both the delta-seconds and HTTP-date forms; |
| 37 | +``parse_ratelimit`` reads the ``RateLimit-Limit/Remaining/Reset`` convention; |
| 38 | +``next_delay`` combines them into the wait a flow should observe after a |
| 39 | +``429`` / ``503``. |
| 40 | + |
| 41 | +Executor commands |
| 42 | +----------------- |
| 43 | + |
| 44 | +``AC_bulkhead_run`` runs an ``actions`` list under a named bulkhead (``name``, |
| 45 | +``max_concurrent``) and returns ``{entered, in_flight, record?}``. |
| 46 | +``AC_retry_after`` takes an HTTP ``response`` (``{status, headers}``) and returns |
| 47 | +``{delay}``. Both are exposed as MCP tools (``ac_bulkhead_run`` / |
| 48 | +``ac_retry_after``) and as Script Builder commands under **Flow**. |
0 commit comments