feat(scheduler-dispatch-commit): add dispatch-fail retry counter to job_t (task 1.3)
Add uint32_t dispatch_fail_count to the job_t wrapper struct (xce/types.h, alongside submit_lsn, same in-memory-only/reset-on-failover precedent), per Requirement 4.3. Data model only -- xce_job_t (wire type) untouched, job.c untouched; increment/reset wiring and the bounded-retry threshold check are tasks 3.1/3.3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
8eea74909c
commit
19bbac6ae0
5 changed files with 111 additions and 1 deletions
|
|
@ -15,7 +15,7 @@
|
|||
- _Requirements: 2.4_
|
||||
- _Boundary: WAL Dispatch Fact_
|
||||
|
||||
- [ ] 1.3 (P) Track how many consecutive times a job's dispatch has failed for a retryable reason
|
||||
- [x] 1.3 (P) Track how many consecutive times a job's dispatch has failed for a retryable reason
|
||||
- Add an in-memory counter on the controller's job record that increments on each retryable dispatch failure and resets to zero on a successful dispatch
|
||||
- This counter does not need to survive a controller failover — resetting to zero after a failover is an acceptable, safe degradation
|
||||
- Observable completion: the counter can be incremented, read, and reset independently of any actual dispatch attempt
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ controller_unit_test_src = [
|
|||
'testsuite/test_apply_committed_entry.c',
|
||||
'testsuite/test_replay_apply_seam.c',
|
||||
'testsuite/test_wal_job_dispatch_fact.c',
|
||||
'testsuite/test_job_dispatch_fail_count.c',
|
||||
'testsuite/test_apply_reapply_idempotency.c',
|
||||
'testsuite/test_apply_correctness_verification.c',
|
||||
'testsuite/test_apply_pump.c',
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ extern void test_apply_seam(void);
|
|||
extern void test_apply_committed_entry(void);
|
||||
extern void test_replay_apply_seam(void);
|
||||
extern void test_wal_job_dispatch_fact(void);
|
||||
extern void test_job_dispatch_fail_count(void);
|
||||
extern void test_apply_reapply_idempotency(void);
|
||||
extern void test_apply_correctness_verification(void);
|
||||
extern void test_apply_pump(void);
|
||||
|
|
@ -249,6 +250,7 @@ int main(int argc, char* argv[])
|
|||
TEST(test_apply_committed_entry);
|
||||
TEST(test_replay_apply_seam);
|
||||
TEST(test_wal_job_dispatch_fact);
|
||||
TEST(test_job_dispatch_fail_count);
|
||||
TEST(test_apply_reapply_idempotency);
|
||||
TEST(test_apply_correctness_verification);
|
||||
TEST(test_apply_pump);
|
||||
|
|
|
|||
98
src/controller/testsuite/test_job_dispatch_fail_count.c
Normal file
98
src/controller/testsuite/test_job_dispatch_fail_count.c
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* test_job_dispatch_fail_count.c — scheduler-dispatch-commit task 1.3
|
||||
*
|
||||
* Proves job_t.dispatch_fail_count (xce/types.h) -- a new in-memory-only
|
||||
* uint32_t counter on the job_t wrapper ({xce_job_t job; uint64_t
|
||||
* submit_lsn;}), NOT on xce_job_t itself -- exists and behaves as a plain,
|
||||
* directly settable/readable/resettable scalar (Requirement 4.3, design.md
|
||||
* "Logical Data Model": "in-memory only... following submit_lsn's exact
|
||||
* precedent... recomputed... never serialized").
|
||||
*
|
||||
* This task is the data-model addition ONLY. It does NOT wire any
|
||||
* increment/reset call site into dispatch_a_job_() (task 3.1/3.3's job) and
|
||||
* does NOT implement the bounded-retry threshold check (also task 3.3).
|
||||
* Every test here manipulates the field directly on a bare stack-local
|
||||
* job_t -- no jobmgr/RTTI/makeJob machinery -- mirroring
|
||||
* test_persist_types.c's test_slot_key_t_fields precedent for a plain
|
||||
* struct-field addition, since this is not a behavioral/dispatch-path test.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unity/unity.h>
|
||||
|
||||
#include "xce/types.h"
|
||||
|
||||
static void test_dispatch_fail_count_default_zero(void)
|
||||
{
|
||||
job_t j;
|
||||
memset(&j, 0, sizeof(j));
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT32(0, j.dispatch_fail_count);
|
||||
printf("test_dispatch_fail_count_default_zero: PASS\n");
|
||||
}
|
||||
|
||||
static void test_dispatch_fail_count_increments_independently(void)
|
||||
{
|
||||
job_t j;
|
||||
memset(&j, 0, sizeof(j));
|
||||
|
||||
/* Simulates 3 consecutive retryable dispatch failures with no
|
||||
* intervening successful dispatch (Requirement 4.3) -- incremented
|
||||
* directly, with no actual dispatch attempt involved. */
|
||||
j.dispatch_fail_count++;
|
||||
TEST_ASSERT_EQUAL_UINT32(1, j.dispatch_fail_count);
|
||||
|
||||
j.dispatch_fail_count++;
|
||||
j.dispatch_fail_count++;
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(3, j.dispatch_fail_count,
|
||||
"counter must be incrementable directly, independent of any actual "
|
||||
"dispatch attempt (Observable completion)");
|
||||
printf("test_dispatch_fail_count_increments_independently: PASS\n");
|
||||
}
|
||||
|
||||
static void test_dispatch_fail_count_resets_to_zero(void)
|
||||
{
|
||||
job_t j;
|
||||
memset(&j, 0, sizeof(j));
|
||||
|
||||
j.dispatch_fail_count = 7;
|
||||
TEST_ASSERT_EQUAL_UINT32(7, j.dispatch_fail_count);
|
||||
|
||||
/* A successful dispatch resets the counter to zero -- task 3.1/3.3 wire
|
||||
* the real call site; this proves the field itself supports the
|
||||
* reset-to-zero operation the design requires, independent of any
|
||||
* actual dispatch attempt. */
|
||||
j.dispatch_fail_count = 0;
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(0, j.dispatch_fail_count,
|
||||
"counter must be independently resettable to zero, matching "
|
||||
"submit_lsn's in-memory-only precedent (no durability obligation, "
|
||||
"safe to lose across a controller failover)");
|
||||
printf("test_dispatch_fail_count_resets_to_zero: PASS\n");
|
||||
}
|
||||
|
||||
static void test_dispatch_fail_count_does_not_alias_submit_lsn(void)
|
||||
{
|
||||
job_t j;
|
||||
memset(&j, 0, sizeof(j));
|
||||
|
||||
j.submit_lsn = 12345;
|
||||
j.dispatch_fail_count = 6;
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT64(12345, j.submit_lsn);
|
||||
TEST_ASSERT_EQUAL_UINT32_MESSAGE(6, j.dispatch_fail_count,
|
||||
"dispatch_fail_count must be its own field on job_t, distinct from "
|
||||
"submit_lsn (both in-memory-only siblings on the wrapper struct)");
|
||||
printf("test_dispatch_fail_count_does_not_alias_submit_lsn: PASS\n");
|
||||
}
|
||||
|
||||
void test_job_dispatch_fail_count(void)
|
||||
{
|
||||
UnitySetTestFile(__FILE__);
|
||||
printf("\n>> job_t.dispatch_fail_count test\n\n");
|
||||
|
||||
RUN_TEST(test_dispatch_fail_count_default_zero);
|
||||
RUN_TEST(test_dispatch_fail_count_increments_independently);
|
||||
RUN_TEST(test_dispatch_fail_count_resets_to_zero);
|
||||
RUN_TEST(test_dispatch_fail_count_does_not_alias_submit_lsn);
|
||||
}
|
||||
|
|
@ -487,6 +487,15 @@ typedef struct {
|
|||
* serialized (wire type xce_job_t above is untouched). 0 = unknown /
|
||||
* pre-feature = always exportable (see job_submit_committed, cluster.h). */
|
||||
uint64_t submit_lsn;
|
||||
/* scheduler-dispatch-commit (1.3): consecutive retryable dispatch-failure
|
||||
* count for this job, with no intervening successful dispatch. In-memory
|
||||
* only, following submit_lsn's exact precedent above — never serialized
|
||||
* (wire type xce_job_t above is untouched), reset to 0 by a successful
|
||||
* dispatch. Resetting to 0 after a controller failover is an acceptable,
|
||||
* safe degradation (more retries allowed, never fewer, never a
|
||||
* misrouted terminal/retry decision) — see Controller Dispatch-Failure
|
||||
* Classification, design.md. */
|
||||
uint32_t dispatch_fail_count;
|
||||
} job_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue