feat(cluster): bidirektionaler Peer-Heartbeat (Primary→Secondary Push) — v1.2.97
Bisher pushte nur der Secondary seine Liveness an den Primary (runPrimaryPush). Der Primary pushte nichts → in der lokalen ha_nodes des Secondary fror die Primary-Row nach dem Boot ein → die vom Secondary ausgelieferte UI zeigte den Primary als offline. Neu: runPeerPush auf dem Primary/Founder pusht alle 30s self (role=primary) an jeden Peer via mTLS (/agent/cluster/peers). PushSelfToPeer(role) generalisiert PushSelfToPrimary; registerPeerRequest+AgentRegisterPeer akzeptieren ein role-Feld (default 'peer' → joining-Peer-Verhalten unverändert). Peer-Register-Log bei Routine-Pushes auf Debug (Info nur bei neuem Peer/IP-Wechsel) gegen 30s-Spam. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -128,7 +128,7 @@ func Join(req Request) error {
|
||||
// synchronous on the primary side.
|
||||
var autoRegErr error
|
||||
for i := 0; i < 3; i++ {
|
||||
if err := autoRegister(primary, tlsDir, req.CommonName, req.Version, req.NodeID, ""); err == nil {
|
||||
if err := autoRegister(primary, tlsDir, req.CommonName, req.Version, req.NodeID, "", "peer"); err == nil {
|
||||
autoRegErr = nil
|
||||
break
|
||||
} else {
|
||||
@@ -222,13 +222,21 @@ func issueCert(primary, token, csr string, insecure bool) (caCert, peerCert stri
|
||||
// goroutine so the primary's ha_nodes always reflects the secondary's actual
|
||||
// config_hash (not the stale join-time value).
|
||||
func PushSelfToPrimary(primaryURL, tlsDir, nodeID, fqdn, version, configHash string) error {
|
||||
return PushSelfToPeer(primaryURL, tlsDir, nodeID, fqdn, version, configHash, "peer")
|
||||
}
|
||||
|
||||
// PushSelfToPeer sendet die eigene Identität an einen beliebigen Peer (mTLS,
|
||||
// /agent/cluster/peers). role bestimmt, mit welcher Rolle sich dieser Node
|
||||
// beim Empfänger einträgt: ein Secondary pusht "peer" an den Primary, der
|
||||
// Primary pusht "primary" an jeden Secondary (bidirektionaler Heartbeat).
|
||||
func PushSelfToPeer(peerURL, tlsDir, nodeID, fqdn, version, configHash, role string) error {
|
||||
if tlsDir == "" {
|
||||
tlsDir = clustertls.DefaultDir
|
||||
}
|
||||
return autoRegister(primaryURL, tlsDir, fqdn, version, nodeID, configHash)
|
||||
return autoRegister(peerURL, tlsDir, fqdn, version, nodeID, configHash, role)
|
||||
}
|
||||
|
||||
func autoRegister(primary, tlsDir, commonName, version, nodeID, configHash string) error {
|
||||
func autoRegister(primary, tlsDir, commonName, version, nodeID, configHash, role string) error {
|
||||
u, err := url.Parse(primary)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -241,6 +249,9 @@ func autoRegister(primary, tlsDir, commonName, version, nodeID, configHash strin
|
||||
nodeID = strings.TrimSpace(string(raw))
|
||||
}
|
||||
hostname, _ := os.Hostname()
|
||||
if role == "" {
|
||||
role = "peer"
|
||||
}
|
||||
body, _ := json.Marshal(map[string]string{
|
||||
"id": nodeID,
|
||||
"name": hostname,
|
||||
@@ -248,6 +259,7 @@ func autoRegister(primary, tlsDir, commonName, version, nodeID, configHash strin
|
||||
"api_url": "https://" + commonName + ":3443",
|
||||
"version": version,
|
||||
"config_hash": configHash,
|
||||
"role": role,
|
||||
})
|
||||
|
||||
pair, err := tls.LoadX509KeyPair(tlsDir+"/peer.crt", tlsDir+"/peer.key")
|
||||
|
||||
Reference in New Issue
Block a user