Skip to content

fix: resolve busy-loop in heartbeat ServerHandler causing high CPU#134

Open
medcl wants to merge 2 commits into
mainfrom
release/v1.25.2
Open

fix: resolve busy-loop in heartbeat ServerHandler causing high CPU#134
medcl wants to merge 2 commits into
mainfrom
release/v1.25.2

Conversation

@medcl

@medcl medcl commented Jul 3, 2026

Copy link
Copy Markdown
Member

The ServerHandler registration loop ignored conn.Read errors and return length. When a client connects then immediately disconnects (e.g. port scan, health check probe), Read returns (0, io.EOF) which was ignored, causing an infinite busy-loop of read()+write() syscalls that pins CPU in kernel mode and leaks goroutines permanently.

Changes:

  • Check conn.Read error and byte count; return on error to release goroutine
  • Use data[2:n] instead of data[2:] for uid to avoid reading garbage
  • Add 30s read deadline during registration phase as safety net
  • Add read lock protection for concurrent CMap access in PushGRT and ServerWHandler to prevent data race
  • Add 100ms backoff in accept loop on error to prevent tight spin

Fixes: GATEWAY-CPU-HIGH (goroutine leak via port 61111 heartbeat server)

What does this PR do

Rationale for this change

Standards checklist

  • The PR title is descriptive
  • The commit messages are semantic
  • Necessary tests are added
  • Updated the release notes
  • Necessary documents have been added if this is a new feature
  • Performance tests checked, no obvious performance degradation

medcl added 2 commits July 3, 2026 18:04
The ServerHandler registration loop ignored conn.Read errors and return
length. When a client connects then immediately disconnects (e.g. port
scan, health check probe), Read returns (0, io.EOF) which was ignored,
causing an infinite busy-loop of read()+write() syscalls that pins CPU
in kernel mode and leaks goroutines permanently.

Changes:
- Check conn.Read error and byte count; return on error to release goroutine
- Use data[2:n] instead of data[2:] for uid to avoid reading garbage
- Add 30s read deadline during registration phase as safety net
- Add read lock protection for concurrent CMap access in PushGRT and
  ServerWHandler to prevent data race
- Add 100ms backoff in accept loop on error to prevent tight spin

Fixes: GATEWAY-CPU-HIGH (goroutine leak via port 61111 heartbeat server)
…odules

heartbeat/client.go:
- Replace close-then-send pattern with sync.Once based Stop()
- Add signalDone() helper to safely signal disconnection without
  panicking on closed channel
- Use buffered select for Rch writes to prevent blocking
- Add Dch select case in ClientWHandler/ClientWork to enable clean exit

heartbeat/server.go:
- Add timeout (2s) on PushGRT channel write to prevent permanent
  deadlock when consumer goroutine dies

floating_ip/floating_ip.go:
- Use buffered aliveChan (cap 1) in SwitchToStandbyMode and StateMachine
  to prevent goroutine leak from double-send to unbuffered channel
- Use non-blocking select for all aliveChan sends to handle race
  between defer, onConnect, and onDisconnect callbacks

floating_ip/broadcast.go:
- Continue on UDP ReadFromUDP error instead of passing nil/zero data
  to handler function
@medcl medcl force-pushed the release/v1.25.2 branch from 02d9327 to c20d153 Compare July 4, 2026 02:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant