feat(xce-test-e2e-primitives): wait-primary [timeout_ms] (task 6.1)
This commit is contained in:
parent
f3334c0fb6
commit
9466b71691
2 changed files with 101 additions and 1 deletions
|
|
@ -119,6 +119,7 @@ extern int cmd_jobinfo(int, char*[]);
|
|||
extern int cmd_echo(int, char*[]);
|
||||
extern int cmd_expect_jobs(int, char*[]);
|
||||
extern int cmd_expect_job(int, char*[]);
|
||||
extern int cmd_wait_primary(int, char*[]);
|
||||
static int worker_house_keeping(void*);
|
||||
|
||||
/* Session verdict / loop state (xce-test-e2e-primitives task 1.1).
|
||||
|
|
@ -205,6 +206,8 @@ static command_t client_commands[] = {
|
|||
{ "joblist", cmd_joblist, "list jobs" },
|
||||
{ "expect-jobs", cmd_expect_jobs, "assert current job count" },
|
||||
{ "expect-job", cmd_expect_job, "assert a JobId is present" },
|
||||
{ "wait-primary", cmd_wait_primary,
|
||||
"wait until a primary serves [timeout_ms]" },
|
||||
{ "shutdown", cmd_shutdown, "shutdown xce controller" },
|
||||
{ "jobrun", cmd_jobrun, "run a job" },
|
||||
{ "jobsub", cmd_jobsub, "submit a job" },
|
||||
|
|
@ -1072,6 +1075,102 @@ 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).
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The timeout is argv[1] in milliseconds when supplied, else
|
||||
* WAIT_PRIMARY_DEFAULT_MS (Req 4.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 */
|
||||
#define MS_PER_SEC 1000L
|
||||
#define NS_PER_MS 1000000L
|
||||
#define US_PER_MS 1000L
|
||||
|
||||
static long monotonic_ms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
return ((long)ts.tv_sec * MS_PER_SEC) + (ts.tv_nsec / NS_PER_MS);
|
||||
}
|
||||
|
||||
int cmd_wait_primary(int argc, char* argv[])
|
||||
{
|
||||
long timeout_ms = WAIT_PRIMARY_DEFAULT_MS;
|
||||
long start_ms, elapsed_ms;
|
||||
|
||||
if (argc > 2) {
|
||||
printf("wait-primary [timeout_ms]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
char* end;
|
||||
|
||||
errno = 0;
|
||||
timeout_ms = strtol(argv[1], &end, 10);
|
||||
|
||||
if ((errno != 0) || (end == argv[1]) || (*end != '\0')
|
||||
|| (timeout_ms < 0)) {
|
||||
printf("wait-primary: invalid timeout '%s' (expected a "
|
||||
"non-negative integer in ms)\n",
|
||||
argv[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
start_ms = monotonic_ms();
|
||||
|
||||
/* 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. */
|
||||
for (;;) {
|
||||
int rc = joblist_query(NULL, NULL, 0);
|
||||
|
||||
if (rc >= 0) {
|
||||
elapsed_ms = monotonic_ms() - start_ms;
|
||||
printf("wait-primary: primary serving after %ld ms\n", elapsed_ms);
|
||||
return 0;
|
||||
}
|
||||
|
||||
elapsed_ms = monotonic_ms() - start_ms;
|
||||
|
||||
if (elapsed_ms >= timeout_ms) {
|
||||
printf("wait-primary: no primary served within %ld ms (waited "
|
||||
"%ld ms)\n",
|
||||
timeout_ms, elapsed_ms);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Don't oversleep past the deadline: cap the poll to the time left. */
|
||||
{
|
||||
long remaining_ms = timeout_ms - elapsed_ms;
|
||||
long sleep_ms = (remaining_ms < WAIT_PRIMARY_POLL_MS)
|
||||
? remaining_ms
|
||||
: WAIT_PRIMARY_POLL_MS;
|
||||
|
||||
if (sleep_ms > 0) {
|
||||
usleep((useconds_t)(sleep_ms * US_PER_MS));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_jobinfo(xce_job_t* job)
|
||||
{
|
||||
char idstring[128];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue