From 842b9a838e3464dfc397a50cf9d1194373b9093b Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Sun, 31 May 2026 11:37:52 +0000 Subject: [PATCH] fix(election): no-config standbys wait passively for primary push instead of polling --- src/controller/myapp.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/controller/myapp.c b/src/controller/myapp.c index 26fa4e80..32dc979b 100644 --- a/src/controller/myapp.c +++ b/src/controller/myapp.c @@ -252,12 +252,17 @@ int myapp_run(myconf_t *myconf) skip_election:; - /* If we skipped starting our own election (already voted for the winner), - * set role to CTRL_STANDBY and trigger config fetch so we can join the cluster. */ + /* Nodes that skipped election (already voted or no config) are now STANDBY. + * Nodes that already have a config actively fetch it so they can connect to + * the primary. Nodes with no config (my_tag == 0) wait passively — the + * primary will push the config via ctrlhello after winning the election + * (Req 7.3). Triggering fetch_config_from_primary for no-config nodes + * only causes retry warnings since the primary isn't up yet. */ { ctrl_role_t role = (ctrl_role_t)atomic_load_explicit(&c.ha.role, memory_order_acquire); - if (role == CTRL_STANDBY || role == CTRL_INIT) { + uint64_t my_tag = c.myconf ? c.myconf->config_version_tag : 0; + if ((role == CTRL_STANDBY || role == CTRL_INIT) && my_tag > 0) { atomic_store_explicit(&c.ha.role, (int32_t)CTRL_STANDBY, memory_order_release); extern int fetch_config_from_primary(cluster_t *c); @@ -265,6 +270,11 @@ skip_election:; * blocking fetch starts (fetch runs in delaymgr worker thread). */ delay_task_ms(&c.delaymgr, 200, 1, (delay_task_entry_fn_t)fetch_config_from_primary, &c); + } else if (role == CTRL_STANDBY || role == CTRL_INIT) { + /* No config — stay STANDBY, wait for primary push (Req 7.3). */ + atomic_store_explicit(&c.ha.role, (int32_t)CTRL_STANDBY, + memory_order_release); + INFO("myapp_run: no local config — waiting for primary to push config"); } }