feat(controller-status): wait-primary uses authoritative ctrlstatus_primary probe (task 4.2)
This commit is contained in:
parent
9e87d2c92e
commit
6747304184
2 changed files with 45 additions and 24 deletions
|
|
@ -49,7 +49,7 @@
|
|||
- _Requirements: 1.3, 3.3, 5.1, 5.2, 8.1, 8.2, 8.3_
|
||||
- _Boundary: cmd_ctrlstatus_
|
||||
- _Depends: 3.1_
|
||||
- [ ] 4.2 Switch wait-primary to the authoritative status probe
|
||||
- [x] 4.2 Switch wait-primary to the authoritative status probe
|
||||
- Replace the wait-primary probe (currently a job-list call) with the authoritative reach-the-primary status call. Success is an authoritative reply from the primary; on success, print the primary's identity. A standby/hint answer is not success — the probe follows the redirect or keeps polling until the primary answers or the deadline elapses. Preserve the existing timeout-argument handling, monotonic deadline, poll interval, log-quieting, and success/failure exit semantics.
|
||||
- Observable: against a healthy cluster wait-primary returns and names the primary; a malformed timeout still errors; the existing exit-code behavior is unchanged; and it does not succeed from a standby-only answer.
|
||||
- _Requirements: 9.1, 9.2, 9.3, 9.4_
|
||||
|
|
|
|||
|
|
@ -1083,23 +1083,28 @@ int cmd_expect_job(int argc, char* argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* `wait-primary [timeout_ms]` (xce-test-e2e-primitives task 6.1, Req 4.1-4.4,
|
||||
* design.md cmd_wait_primary).
|
||||
/* `wait-primary [timeout_ms]` (controller-status task 4.2, Req 9.1-9.4;
|
||||
* originally xce-test-e2e-primitives task 6.1; design.md "cmd_wait_primary probe
|
||||
* swap — State contract").
|
||||
*
|
||||
* Blocks until a cheap, failover-aware client op succeeds, or the timeout
|
||||
* elapses. The probe is the print-free joblist_query(NULL, NULL, 0): it drives
|
||||
* active_ctx + libxce master-rotation/failover and returns a job count (>= 0)
|
||||
* only when a primary actually served the request, or < 0 on error (Req 4.1).
|
||||
* Blocks until the AUTHORITATIVE controller status probe reaches the serving
|
||||
* primary, or the timeout elapses. The probe is xcecli_ctrlstatus_primary: it
|
||||
* drives active_ctx + libxce master-rotation/failover and returns 0 ONLY when a
|
||||
* reply with responderRole == PRIMARY was obtained (it internally follows the
|
||||
* redirect to the primary), or a typed negative when no primary answered within
|
||||
* its budget (Req 9.1). A standby/hint answer is NOT success — the probe keeps
|
||||
* polling until the primary itself answers (this avoids a false success on a
|
||||
* standby's stale primary view after a primary death).
|
||||
*
|
||||
* On the first successful probe we return 0 (Req 4.2). Otherwise we sleep a
|
||||
* short poll interval and retry, re-checking a MONOTONIC deadline between
|
||||
* attempts so the command returns within a bounded time of the timeout and
|
||||
* never hangs indefinitely when there is no primary (Req 4.3). The deadline is
|
||||
* derived from CLOCK_MONOTONIC, never wall-clock, so a clock step cannot skew
|
||||
* it.
|
||||
* On the first authoritative probe we print the served primary's identity and
|
||||
* return 0 (Req 9.2). Otherwise we sleep a short poll interval and retry,
|
||||
* re-checking a MONOTONIC deadline between attempts so the command returns
|
||||
* within a bounded time of the timeout and never hangs indefinitely when there
|
||||
* is no primary (Req 9.3). The deadline is derived from CLOCK_MONOTONIC, never
|
||||
* wall-clock, so a clock step cannot skew it.
|
||||
*
|
||||
* The timeout is argv[1] in milliseconds when supplied, else
|
||||
* WAIT_PRIMARY_DEFAULT_MS (Req 4.4). A malformed timeout argument is a usage
|
||||
* WAIT_PRIMARY_DEFAULT_MS (Req 9.4). A malformed timeout argument is a usage
|
||||
* error (return < 0) rather than a silent fallback to the default. */
|
||||
#define WAIT_PRIMARY_DEFAULT_MS 30000L /* default max wait when arg omitted */
|
||||
#define WAIT_PRIMARY_POLL_MS 200L /* sleep between probe attempts */
|
||||
|
|
@ -1149,26 +1154,42 @@ int cmd_wait_primary(int argc, char* argv[])
|
|||
start_ms = monotonic_ms();
|
||||
|
||||
/* The poll probes repeatedly and EXPECTS failure until a primary serves, so
|
||||
* it must not spam the console: the probe suppresses its own error print
|
||||
* (quiet=1), and we raise the client log threshold for the duration of the
|
||||
* loop to silence libxce's per-attempt "xcecli failover: attempt N" INFO
|
||||
* logs — RESTORED to the user's level on every exit path. */
|
||||
* it must not spam the console: xcecli_ctrlstatus_primary suppresses its own
|
||||
* per-attempt output, and we raise the client log threshold for the duration
|
||||
* of the loop to silence libxce's per-attempt "xcecli failover: attempt N"
|
||||
* INFO logs — RESTORED to the user's level on every exit path. */
|
||||
mylog_setlevel((char*)"warn");
|
||||
|
||||
/* Probe, then re-check the monotonic deadline between attempts. Each probe
|
||||
* may itself take time (libxce failover has its own internal retry budget);
|
||||
* we re-read the clock after every probe returns so the overall loop honors
|
||||
* the deadline and returns failure in bounded time. */
|
||||
* may itself take time (libxce failover + redirect-to-primary has its own
|
||||
* internal retry budget); we re-read the clock after every probe returns so
|
||||
* the overall loop honors the deadline and returns failure in bounded time. */
|
||||
for (;;) {
|
||||
int rc = joblist_query(NULL, NULL, 0, /*quiet=*/1);
|
||||
xce_ctrlstatus_t* status = NULL;
|
||||
int rc = xcecli_ctrlstatus_primary(active_ctx->ctx,
|
||||
&status);
|
||||
|
||||
/* Success ONLY on an authoritative reply from the serving primary
|
||||
* (responderRole == PRIMARY, guaranteed by xcecli_ctrlstatus_primary).
|
||||
* Print the served primary's identity (the responder IS the primary, so
|
||||
* primaryName == responderName) and free the reply (Req 9.1, 9.2). */
|
||||
if (rc == 0) {
|
||||
const char* primary = (status != NULL)
|
||||
? (NULLSTR(status->primaryName)
|
||||
? status->responderName
|
||||
: status->primaryName)
|
||||
: NULL;
|
||||
|
||||
if (rc >= 0) {
|
||||
elapsed_ms = monotonic_ms() - start_ms;
|
||||
mylog_setlevel(g_active_loglevel);
|
||||
printf("wait-primary: primary serving after %ld ms\n", elapsed_ms);
|
||||
printf("wait-primary: primary '%s' serving after %ld ms\n",
|
||||
NULLSTR(primary) ? "unknown" : primary, elapsed_ms);
|
||||
xcecli_free_ctrlstatus(status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Non-authoritative / failed probe: nothing to free (the typed-failure
|
||||
* contract leaves *status untouched), keep polling until the deadline. */
|
||||
elapsed_ms = monotonic_ms() - start_ms;
|
||||
|
||||
if (elapsed_ms >= timeout_ms) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue