Commit d021b3e
fix(mcp): optimistic-lock concurrent MCP server PATCHes (#14005)
* fix(mcp): optimistic-lock concurrent MCP server PATCHes
Follow-up to #13976. A concurrent merge PATCH to the same MCP server could still lose a field: two PATCHes read the same row and the last commit wins, dropping the other's change. Guard the merge-PATCH write with the existing version column (UPDATE ... WHERE id=? AND version=?); on a 0-row result, re-read, re-merge, and retry. A full replace stays last-writer-wins (unconditional update) so it never contends and cannot exhaust the retry budget. Adds a regression test running concurrent distinct-field PATCHes that asserts all survive.
* fix(mcp): return 404/409 instead of 500 for not-found/conflict
Per review on #14005: a concurrently-deleted server during a merge PATCH, a missing server on delete, and a duplicate on create are client outcomes, not server faults. Return 404 (not found) and 409 (conflict) so they don't trip 5xx error handling. Applied consistently across update_server.
* fix(mcp): address review feedback on the optimistic-lock PATCH
Per review of #14005: (1) full replace bumps the version DB-side (version = MCPServer.version + 1) so it stays monotonic even off a stale ORM read, instead of reusing a version a concurrent PATCH consumed; (2) the create-race handler re-raises when no winning row exists after refetch, so a genuine IntegrityError surfaces instead of retrying to a misleading 409; (3) replaced the probabilistic PATCH-vs-DELETE test with a deterministic one asserting the PATCH returns exactly 404, and added a regression test that injects a concurrent version advance between the replace's read and write to prove monotonicity.
* [autofix.ci] apply automated fixes
* [autofix.ci] apply automated fixes
* [autofix.ci] apply automated fixes (attempt 2/3)
* fix(mcp): re-create when a full replace races a concurrent delete
The merge-PATCH path already turns a row deleted between its read and its
guarded UPDATE into a clean 404. The full-replace path never checked
rowcount: the same race made its unguarded UPDATE match nothing, the loop
broke, and the request returned None with the write silently lost.
Check rowcount after the replace UPDATE; on a miss, re-read the row and
loop. A still-missing row takes the create path on the next iteration, so
the replace converges to a re-create (fresh row, version 1) instead of a
silent no-op. Covered by a race-injection test in the same style as
test_patch_losing_to_concurrent_delete_returns_404.
* [autofix.ci] apply automated fixes
---------
Co-authored-by: Saad ur Rehman <saad.urrehman@cleura.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Eric Hare <ericrhare@gmail.com>1 parent 683eae6 commit d021b3e
5 files changed
Lines changed: 265 additions & 63 deletions
File tree
- src/backend
- base/langflow
- api/v2
- initial_setup/starter_projects
- tests/unit/api/v2
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| |||
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
31 | 35 | | |
32 | 36 | | |
33 | 37 | | |
| |||
406 | 410 | | |
407 | 411 | | |
408 | 412 | | |
409 | | - | |
| 413 | + | |
410 | 414 | | |
411 | 415 | | |
412 | 416 | | |
| |||
415 | 419 | | |
416 | 420 | | |
417 | 421 | | |
418 | | - | |
419 | | - | |
420 | | - | |
421 | | - | |
422 | | - | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
423 | 428 | | |
| 429 | + | |
424 | 430 | | |
425 | 431 | | |
426 | 432 | | |
427 | 433 | | |
428 | | - | |
429 | | - | |
430 | | - | |
431 | | - | |
432 | | - | |
433 | 434 | | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
434 | 439 | | |
435 | | - | |
| 440 | + | |
436 | 441 | | |
437 | 442 | | |
438 | 443 | | |
439 | 444 | | |
440 | 445 | | |
441 | | - | |
442 | | - | |
443 | | - | |
444 | | - | |
445 | | - | |
446 | | - | |
447 | | - | |
448 | | - | |
449 | | - | |
450 | | - | |
451 | | - | |
452 | | - | |
453 | | - | |
454 | | - | |
| 446 | + | |
| 447 | + | |
455 | 448 | | |
456 | | - | |
457 | | - | |
458 | | - | |
459 | | - | |
460 | | - | |
461 | | - | |
462 | | - | |
463 | | - | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
464 | 452 | | |
465 | | - | |
466 | | - | |
467 | | - | |
468 | | - | |
469 | | - | |
470 | | - | |
471 | | - | |
472 | | - | |
473 | | - | |
474 | | - | |
475 | | - | |
476 | 453 | | |
477 | | - | |
478 | | - | |
479 | | - | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
480 | 479 | | |
481 | 480 | | |
482 | 481 | | |
483 | | - | |
484 | | - | |
485 | | - | |
486 | | - | |
487 | | - | |
488 | | - | |
489 | | - | |
490 | | - | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
491 | 519 | | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
492 | 532 | | |
493 | 533 | | |
494 | | - | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
495 | 537 | | |
496 | 538 | | |
497 | 539 | | |
| |||
0 commit comments