fix(ha-bootstrap): three startup fixes for election reliability

1. iomgr_monitor double-register: cluster_start skips iomgr_monitor
   if c->ep was already registered by cluster_register_listener
   (ep->flags non-zero after successful registration). Previously
   returned EEXIST → -1 → "Operation not permitted" crash.

2. ASAN stack-use-after-return: cluster_fini now calls iomgr_stop()
   before iomgr_fini() to join the worker thread before the cluster_t
   stack frame is reclaimed by the caller.

3. Election timing: add ha_wait_for_heartbeat_or_timeout() before
   election in myapp_run. If an existing primary sends a heartbeat,
   node becomes STANDBY immediately without competing in election.
   If timeout expires (no primary running), proceed to election.
   This prevents ctrl-a from immediately losing when ctrl-b/c are
   not yet started — it now waits election_timeout_ms (2s) first.
This commit is contained in:
Rongsong Shen 2026-05-30 00:28:10 +00:00
parent fc77630e6c
commit 47c09d653c
2 changed files with 38 additions and 35 deletions

View file

@ -1119,10 +1119,12 @@ int cluster_start(cluster_t* c)
endpoint_set_conn_handler(&(c->ep), (conn_handler_t)handle_connection);
c->ep.iomgr = &(c->iomgr);
rc = iomgr_monitor(&(c->ep));
if (rc < 0) {
return rc;
/* Skip iomgr_monitor if cluster_register_listener already registered
* this fd with epoll (ep->flags is set on successful registration). */
if (c->ep.flags == 0) {
rc = iomgr_monitor(&(c->ep));
if (rc < 0)
return rc;
}
/* Guard: myapp_run() starts iomgr and vtaskmgr before election so that
@ -1207,6 +1209,7 @@ void cluster_fini(cluster_t* c)
xce_run_hooks(&(c->hooksys), XCE_CONTROLLER_HOOK_CLUSTER, HOOK_AFTER_EVENT,
HOOK_DETAIL_CLUSTER_SHUTDOWN, c);
cbuf_fini(&(c->wbuf));
iomgr_stop(&(c->iomgr)); /* join worker thread before freeing SSL_CTX */
iomgr_fini(&(c->iomgr));
destroy(c->jobmgr);