[Server] Answer a JSON POST with only its own responses - #508
vbcherepanov wants to merge 1 commit into
Conversation
e0fced5 to
64f02a0
Compare
|
Independent confirmation on v0.6.0 (Apache + mod_php), driving a real MCP server rather than a unit test: 20 concurrent
This PR removes the cross-delivery completely — 0 in 140 pairs after it, against 11 in 40 before. Both shapes described in #467 are gone: the JSON array carrying another request's response, and the Two notes from the same runs:
Real-client impact, for the record: Claude Code issues The patch was applied by hand onto v0.6.0 (the files have moved since), so line numbers differ but the logic is unchanged. |
|
Correction to my numbers above, and a data point on v0.8.1. The residual-loss figure in my comment — "one lost response survives both (1 in 60 pairs)" — came from too small a sample. Larger runs put it at 6 in 180 pairs on v0.6.0 with both PRs applied, so roughly 1 in 30. That residual is still the lost update of #275 and still outside this PR's scope, so nothing here changes; I am correcting it because "1 in 60" understates how often a real client ends up waiting on a response that was silently dropped. The cross-delivery result did not move, and it is the one I would stand behind: 0 in 180 pairs. v0.8.1 still has the bug. Same harness against stock v0.8.1: 65 % of pairs correct, versus 67 % on stock v0.6.0. So the v0.8.0 refactor did not incidentally fix this and the PR is still needed against current releases — worth saying explicitly, because the files have moved enough that four hunks had to be finished by hand when porting it there.
One caveat on that 17, since it would be easy to misread as "v0.8.1 loses more than v0.6.0": those runs shared a busy machine and a single run contributed 5 of them. I would not claim a difference between the two bases without re-measuring on an idle box. The zero cross-delivery is the robust part of both patched rows. Same setup as before — Apache + mod_php, 20 concurrent |
Fixes #467.
With PHP-FPM, requests of the same session run in parallel and put their responses into the same session queue.
createJsonResponse()took the whole queue, so one request got all responses as a JSON array and the others got202with nothing.Now the transport collects the ids from its own POST body and takes only those responses. The rest stays in the queue. Batches are still answered with an array, single messages with one object, and an invalid message without a usable id still gets its error.
Protocol::consumeOutgoingMessages()gets the ids as an optional second argument. Without it nothing changes, so the SSE path andStdioTransportwork as before.The reproducer is
testConcurrentPostsSharingASessionEachReceiveTheirOwnResponse: the second POST is handled completely between the first one queueing its response and reading the queue. It fails onmain.Not part of this PR: