feat(component-failover-adoption): trigger apiserver's rejoin from the idle-period heartbeat path
xcecli_heartbeat() is XCECLI_FF_CALL-wrapped -- a deliberately non-retrying fire-and-forget path that does its own best-effort one-shot reconnect but never calls xcecli_invoke_rejoin() (that only fires from the write-call retry path). Left as-is, a controller failover with no in-flight write request would silently repair the transport connection without ever re-joining, permanently starving push notifications. runHeartbeat() gains two callback hooks fired at the right points -- onFailureToSuccess on a genuine transition, onSuccessTick on every successful tick thereafter -- wired directly to task 4.3's existing setNeedsRejoin()/checkAndPerformRejoin() from StartHeartbeat(). No second rejoin mechanism: checkAndPerformRejoin() is a cheap no-op when nothing is pending, so calling it unconditionally on every successful tick is safe and matches the requirement that retry isn't gated on the transition edge alone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NNB4zGPCsHyDUCDJyMbiQN
This commit is contained in:
parent
2a205291c0
commit
ecf5eddc61
5 changed files with 363 additions and 12 deletions
|
|
@ -349,10 +349,17 @@ func Cleanup() {
|
|||
|
||||
// StartHeartbeat launches a goroutine that sends periodic xcecli_heartbeat
|
||||
// keep-alive messages to the controller. Stops when ctx is cancelled.
|
||||
//
|
||||
// Wires runHeartbeat's failure-to-success and every-successful-tick hooks to
|
||||
// reconnect.go's setNeedsRejoin/checkAndPerformRejoin (task 4.3) -- closing
|
||||
// the idle-period reconnect gap (task 4.4, Req 2 AC4/AC5): XCECLI_FF_CALL
|
||||
// (backing xcecli_heartbeat) never invokes the client library's rejoin
|
||||
// callback, so nothing else would set the pending-rejoin flag if this
|
||||
// heartbeat prober is the only traffic during a controller outage.
|
||||
func StartHeartbeat(ctx context.Context) {
|
||||
go runHeartbeat(ctx, func(secs int) {
|
||||
C.xcecli_heartbeat(gCtx.ctx, C.int(secs))
|
||||
})
|
||||
go runHeartbeat(ctx, func(secs int) int {
|
||||
return int(C.xcecli_heartbeat(gCtx.ctx, C.int(secs)))
|
||||
}, setNeedsRejoin, checkAndPerformRejoin)
|
||||
}
|
||||
|
||||
// go_push_handler is called by the C library on every incoming request.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue