Skip to content

Fix idle ping spin loop from exhausted AsyncStream iterator#637

Merged
datlechin merged 1 commit intomainfrom
fix/ping-spin-loop-618
Apr 8, 2026
Merged

Fix idle ping spin loop from exhausted AsyncStream iterator#637
datlechin merged 1 commit intomainfrom
fix/ping-spin-loop-618

Conversation

@datlechin
Copy link
Copy Markdown
Collaborator

Summary

Fixes the root cause of #618 (excessive idle ping traffic, ~30 pings/second instead of 1 per 30s).

Root cause

The health monitor used a task group to race Task.sleep(30s) against AsyncStream.Iterator.next():

await withTaskGroup(of: Bool.self) { group in
    group.addTask { try? await Task.sleep(for: .seconds(30)); return false }
    group.addTask { _ = await wakeIterator.next(); return true }
    if await group.next() != nil { group.cancelAll() }
}

When the 30s sleep won, group.cancelAll() cancelled the wake-up task, causing next() to return nil. An AsyncStream iterator that returns nil is permanently exhausted — all subsequent next() calls return nil instantly. This turned the monitoring loop into a spin loop.

Fix

Removed the AsyncStream + task group race entirely. Replaced with a simple Task.sleep loop:

while !Task.isCancelled {
    try? await Task.sleep(for: .seconds(Self.pingInterval))
    guard !Task.isCancelled else { break }
    await self.performHealthCheck()
}

The checkNow() early wake-up method was dead code (never called anywhere in the codebase), so the AsyncStream mechanism served no purpose.

Also added diagnostic logging to the ping handler for ongoing monitoring.

Closes #618

Test plan

  • Connect to PostgreSQL, leave idle for 2+ minutes — verify pings fire every ~30s (check Console.app filter ConnectionHealthMonitor)
  • Disconnect network → verify auto-reconnect triggers with exponential backoff
  • Reconnect manually via toolbar → verify single monitor running

@datlechin datlechin merged commit 144f01a into main Apr 8, 2026
2 checks passed
@datlechin datlechin deleted the fix/ping-spin-loop-618 branch April 8, 2026 06:02
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.

Excessive idle PostgreSQL ping traffic

1 participant