Repository navigation
feat: send Retry-After on 429 and expose it to the PHP client and the MCP server - #63
Merged
Merged
Conversation
# Conflicts: # CHANGELOG.md # docs/protocol.md # docs/testing.md # src/Client.php # tests/php/integration.php # tests/php/run.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #50.
A full store answered
429 capacity_exceededwith nothing a client could plan on; only the MCP server coped, guessing a doubling backoff. The store now knows when capacity returns:CapacityErrorcarriesretry_afterin whole seconds (at least 1), computed as the earliest retention expiry among finished jobs, or 1 when only unfinished jobs fill the store, when shutting down, or when the job table cannot be written. Every 429 carries an integerRetry-Afterheader.BridgeExceptiongains a nullable readonlyretryAfterSeconds, its last constructor parameter with a default, filled by the client from the header on a 429 when it is one header of 1 to 6 digits; a repeated header yields null in both clients, since a conflicting pair is not a value to trust. Response headers are collected with a 16 KiB cap and refused asinvalid_responsebeyond it, with the state reset at each status line so a100 Continueblock does not count. The client still never retries by itself. The MCP server's protocol client carries the parsed value and its capacity wait uses it when present, bounded by the remaining budget, keeping its own backoff otherwise.docs/protocol.mddocuments the header,docs/integration.mdshows an application scheduling a resubmit from the property, and the changelog has an Unreleased line.Files:
worker/ai_bridge/jobs.py,worker/ai_bridge/server.py,src/BridgeException.php,src/Client.php,mcp_server/bridge_mcp/protocol.py,mcp_server/bridge_mcp/tools.py,tests/python/test_jobs.py,tests/python/test_server.py,tests/php/run.php,tests/php/integration.php(the fault worker filled to capacity and the header read through the real worker),tests/mcp/test_tools.py,tests/mcp/test_protocol.py,docs/protocol.md,docs/integration.md,docs/testing.md,CHANGELOG.md.Checks on this head (merged with main after the SQLite store landed): python-tests 189 OK, php-tests 141, php -l, php-integration 178, FrankenPHP integration, mcp-tests 125 OK, composer-install, php-fetcher, php-analysis
[OK] No errors. Reviews: independent review by Codex (gpt-6-luna), no defects, one untested edge (the repeated header) covered in this commit and confirmed mergeable on a second read.