mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
fix(subprocess): give sanitized builds a wider spawn-retry window
The exponential backoff shipped in v0.10.3 (10/20/40/80/160/320ms, ~0.6s) fixed the ordinary case. `subprocess_run_spawn_failure` then kept failing on `test-tsan (macos-14)` — twice on the same SHA, on a PR whose entire diff was a shell contract plus one line in test.sh, so causation was impossible. ThreadSanitizer runs several times slower and holds far more process state, so the pressure window it creates is simply longer than 0.6s. The budget was right for a normal build and short for a sanitized one. Raising it for everyone would be the wrong fix: an unsanitized machine that is genuinely out of capacity should fail fast rather than hang for seconds. So the extra patience is scoped to the builds that need it — three more doublings, about 5s, under CBM_SANITIZED_BUILD or __SANITIZE_*__ only. Same shape as the daemon announce backstop in test_daemon_frontend.c, and for the same reason. Also fixes a bug in the backoff itself: the shift was capped at a hard-coded 6, so with a budget of 9 the final three waits would have flattened to 320ms each instead of continuing to double — the extra attempts would have bought a third of the intended time. The cap now follows the budget. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
1 parent
7abdd8dc50
commit
a92b6be9e3
1 file changed
+26
-1
@@ -885,7 +885,27 @@ static cbm_proc_poll_t cbm_subprocess_poll_win(cbm_subprocess_t *process, cbm_pr
|
||||
/* Transient spawn-failure retry (see the EAGAIN note in cbm_posix_spawn_apple).
|
||||
* Three attempts over ~30ms total: long enough to ride out a burst of process
|
||||
* creation, short enough that a genuinely exhausted system still fails fast. */
|
||||
/* A sanitized build needs a wider window than an ordinary one, and only a
|
||||
* sanitized one does.
|
||||
*
|
||||
* The exponential backoff (10/20/40/80/160/320ms, ~0.6s) fixed the ordinary
|
||||
* case. `subprocess_run_spawn_failure` then kept failing on `test-tsan` — twice
|
||||
* on one SHA, on a PR whose diff was a shell contract and a line in test.sh, so
|
||||
* causation was impossible. ThreadSanitizer runs several times slower and holds
|
||||
* far more process state, so the pressure window it creates is simply longer
|
||||
* than 0.6s.
|
||||
*
|
||||
* Raising the budget for everyone would be the wrong fix: an unsanitized
|
||||
* machine that is genuinely out of capacity should still fail fast rather than
|
||||
* hang for seconds. So the extra patience is scoped to the builds that need it,
|
||||
* the same way the daemon announce backstop is (test_daemon_frontend.c). Three
|
||||
* more doublings take the sanitized ceiling to roughly 5s. */
|
||||
#if defined(CBM_SANITIZED_BUILD) || defined(__SANITIZE_ADDRESS__) || \
|
||||
defined(__SANITIZE_MEMORY__) || defined(__SANITIZE_THREAD__)
|
||||
enum { CBM_SPAWN_RETRY = 2, CBM_SPAWN_RETRY_ATTEMPTS = 9 };
|
||||
#else
|
||||
enum { CBM_SPAWN_RETRY = 2, CBM_SPAWN_RETRY_ATTEMPTS = 6 };
|
||||
#endif
|
||||
|
||||
/* Exponential backoff: 10, 20, 40, 80, 160, 320ms — ~630ms of total patience.
|
||||
*
|
||||
@@ -921,7 +941,12 @@ static bool cbm_spawn_eagain_injected(void) {
|
||||
#endif
|
||||
|
||||
static void cbm_spawn_backoff(int attempt) {
|
||||
long ms = 10L << (attempt < 6 ? attempt : 6);
|
||||
/* Cap the shift at the budget, not at a constant: with the sanitized budget
|
||||
* of 9 a hard-coded 6 would flatten the last three waits to 320ms each
|
||||
* instead of continuing to double. The budget is the only bound needed —
|
||||
* callers never exceed it, and a second clamp would be dead code. */
|
||||
int shift = attempt < CBM_SPAWN_RETRY_ATTEMPTS ? attempt : CBM_SPAWN_RETRY_ATTEMPTS;
|
||||
long ms = 10L << shift;
|
||||
struct timespec delay = {ms / 1000L, (ms % 1000L) * 1000L * 1000L};
|
||||
(void)cbm_nanosleep(&delay, NULL);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user