Commit graph

15 commits

Author SHA1 Message Date
9cdeba5816 test(ha-commit-barrier-rollout): RED tests for config barrier (task 5.1)
6 RED carriers pinning the three configAck defects (previous-tag acks
count, n_active==0 success shortcut, no-self-count denominator) and the
push/upgrade failure path (logged-only result, unconditional success
ACK + restart). 2 sanctioned pins (single-member, success-unchanged).
Behavior-preserving signature change: push_config_to_standbys gains
acked_out (return still legacy push count; 7 call sites NULL'd,
body-diff verified). 29/6 in group; no collateral failures.
2026-06-12 16:31:42 +00:00
facdb90917 feat(ha-commit-barrier-rollout): commit-first-then-reply in all four handlers (task 3.2)
Uniform pattern (ctrl fn -> persist_commit_barrier -> reply) in
do_jobcontrol_op/do_queuecontrol_op/do_hostcontrol_op; join barrier
between AFTER_EVENT and success reply (failure -> error reply, skip
on_worker_join). FIXES bug-447: key_find found-rc normalized inside
job_ctrl/queue_ctrl/worker_ctrl — queue/host control now actually
append WAL and replicate (was silently unpersisted); idempotent no-ops
now return 0. handle_jobsubmit untouched. 12/12 + 15/15; census zero
failures.
2026-06-12 10:28:25 +00:00
fd93997f78 fix(election-iomgr-refactor): config replication and RDHUP failover chain
- cluster.c: fix upgradeConfig handler (standbys apply, not primaries)
- cluster.c: fix raw_pkt_copy opcode peek (read scalar before capn_free)
- config_repl.h: enable CONF_ENABLE_UPGRADE_CONFIG=1
- config_repl.c: use client_ssl_ctx for outgoing config fetch connections
- config_repl.c: after config fetch, run cluster_init_phase2 + find_primary
- join.c: push config to newly-joined standbys on OPCode_join
- myapp.c: schedule fetch_config_from_primary after skipping own election
- ha.c: arm heartbeat timeout watchdog after find_and_connect_to_primary
2026-05-31 02:08:48 +00:00
86fe35e671 add kiro skills 2026-05-21 03:41:57 +00:00
8f4db308da feat: implement handle_config_request(), fetch_config_from_primary(), handle_controller_join()
- handle_config_request(): primary-side handler sends up-to-date flag or
  version_tag; SHA-256 integrity check guards against in-place file changes;
  sha256/bytes fields left NULL pending Task 11 typemap shims
- fetch_config_from_primary(): standby fetch with exponential backoff retry
  (20 attempts, 500ms..5s); falls back to saved config via load_primary_config();
  do_one_config_fetch() stubbed (-ENOSYS) until Task 11 wires capnp over SSL
- handle_controller_join(): registers standby endpoint in ha.standby_endpoints
  via zarray_store() for OP_upgradeConfig fan-out; sends success reply
- Moved load_primary_config() from myconf.c to config_repl.c so the unit test
  binary (which links config_repl.c but not myconf.c) can resolve it
2026-05-13 17:46:56 +00:00
6429ef0bff fix: correct controller restart recovery — jobs, workers, and resource ordering
Four bugs fixed:

1. persist.c: array job WAL loop aborted after index [0] when replication
   returned -ENODEV (no standbys). Loop guard now uses the return value of
   persist_wal_sync_append() which is 0 on local-disk success regardless of
   replication status.

2. join.c: WAL-recovered worker slot (status=UNAVAIL) caused add_worker() to
   return -EEXIST on reconnect. New EEXIST path in handle_worker_join() looks
   up the existing slot by name, updates its endpoint, and clears UNAVAIL so
   the normal hook/reply/on_worker_join flow proceeds.

3. xcectx.c: cbuf_get() in xce_hello() blocked indefinitely when the TCP
   connection dropped because no error handler was registered. Added
   handle_disconnect() which sets ctx->state=XCE_CTX_ERR and calls
   cbuf_tryput(-ECONNRESET) to unblock the waiter, allowing
   checking_connection() to detect the failure and rejoin.

4. cluster.c: persist_recover() was called before cluster_build_resources()
   populated resmgr, causing restore_worker() → add_hostattrs_resvals() to
   fail with EEXIST noise. Moved persist_recover() to after HOOK_AFTER_EVENT
   so resmgr is fully populated before WAL replay.
2026-05-09 03:02:39 +00:00
9b6a91a89e feat: implement restore_job/worker_from_capnp for WAL recovery
WAL hooks now write real Cap'n Proto payloads instead of stub uint32_t:
- WAL_JOB_SUBMIT: full xce_job_t serialized via encode_Job/write_Job
- WAL_WORKER_CTRL: [uint32_t detail][xce_worker_t capnp] via encode_Worker
- Other job events (START/FINISH/FAIL/STOP etc): uint64_t jobid only

restore_job(): deserializes Cap'n Proto xce_job_t, guards against duplicate
replay with key_find check, then calls create_job()

worker_from_capnp(): skips 4-byte detail prefix, deserializes xce_worker_t,
guards against duplicate replay, then calls restore_worker()

join.c: pass worker_t* (looked up by idx via vget) to WORKER_JOIN hook
so persist hook can serialize worker data without touching workermgr RTTI
2026-05-08 07:49:27 +00:00
f5b0ac0af3 feat: ha_should_redirect + join.c HA redirect/nomaster guard (P1-6)
Add redirect helpers to ha.c/ha.h so a standby controller never accepts
join requests as if it were the primary:

- ha_should_redirect(): returns 1 when role is STANDBY and primary_host/port
  are known — caller should send E_XCE_REDIRECT.
- ha_no_primary_known(): returns 1 when role is STANDBY but primary address
  is not yet known — caller should send E_XCE_NOMASTER (retry later).
- Add E_XCE_NOMASTER and E_XCE_REDIRECT to errnox.h.
- Wire both guards into handle_join_() in join.c (before the role switch)
  so all join types (worker, scheduler, apiserver, client) are protected.
- Full redirect response sends status=-E_XCE_REDIRECT with nodata body;
  the primary host:port are logged so operators can trace misrouted clients.
  Full Cap'n Proto RedirectInfo response body is deferred to a follow-up
  (schema union would require regenerating capnp bindings).

5 new TDD tests — 110 total, 0 failures.
2026-05-07 15:11:53 +00:00
045d9e3287 feat: add HOOK_DETAIL_JOB_STOP/RESUME; fix xce_reply ordering after AFTER_EVENT hooks (P0-4a)
- cluster_def.h: add struct tag `cluster_s` to cluster_t to resolve
  conflicting typedef with persist.h forward declaration
- cluster_def.h: add HOOK_DETAIL_JOB_STOP and HOOK_DETAIL_JOB_RESUME enum
  values after HOOK_DETAIL_JOB_RUSAGE_UPDATE
- job.c on_job_stop(): replace mark_job_update() call with direct
  xce_run_hooks(BEFORE/AFTER, HOOK_DETAIL_JOB_STOP) so WAL writer
  records stop events with the correct detail value
- job.c on_job_resume(): same pattern with HOOK_DETAIL_JOB_RESUME
- job.c do_clr_preason(): fix typo — second hook call was HOOK_BEFORE_EVENT
  instead of HOOK_AFTER_EVENT (double-before, zero-after bug)
- join.c handle_worker_join(): move xce_reply() to after HOOK_AFTER_EVENT
  so client ACK is not sent before WAL write completes (durability fix)
- testsuite/test_hooks.c: new TDD tests for JOB_STOP/RESUME enum values
- testsuite/controller_test.c + meson.build: register test_hooks suite

Reply ordering audit results:
  job.c handle_jobsubmit: reply before AFTER_EVENT — intentional (jobid
    returned to client before scheduler notification; WAL hook belongs in
    BEFORE_EVENT for this path, handled in Task 13)
  job.c do_set_preason: reply before set_preason() loop — intentional
    fire-and-forget (no AFTER_EVENT hook at top level)
  job.c do_clr_preason: reply before loop — same fire-and-forget pattern
  job.c do_jobcontrol_op: no AFTER_EVENT hook, reply only — OK
  join.c handle_worker_join: FIXED (reply moved after AFTER_EVENT)
  worker.c on_worker_update/dead: reply after all hooks — OK
  cluster.c: AFTER_EVENT hooks are internal (no reply) — OK
2026-05-07 12:08:52 +00:00
3f74f14687 save works 2026-03-04 18:18:53 +08:00
44fc5b23e9 push more to api server 2026-01-22 17:23:18 +08:00
70970434ca initial work of api server 2026-01-20 18:20:24 +08:00
79124c6e5c improve join protocol 2025-12-11 14:49:05 +08:00
9ff857db9f reformat code and job array 2025-11-07 16:14:27 +08:00
Rongsong Shen
41f56fa6ed update controller code 2025-11-05 16:58:57 +08:00