Fix remote proxy notification spam with cooldown, backoff, and SSH keepalive (#2325) (#2330)

- Add 5-minute per-host cooldown for remote error notifications
- Add exponential backoff (capped at 60s) to proxy broker and session controller retries
- Add default SSH ConnectTimeout/ServerAliveInterval/ServerAliveCountMax to detect dead connections faster
- Fix error status clearing to only reset on actual .connected state

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Austin Wang 2026-03-29 18:07:39 -07:00 committed by GitHub
parent 9e75355525
commit e419fd9164
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 100 additions and 24 deletions

View file

@ -733,6 +733,7 @@ final class TerminalNotificationStore: ObservableObject {
notification in
store.playSuppressedNotificationFeedback(for: notification)
}
private var lastNotificationDateByCooldownKey: [String: Date] = [:]
private var indexes = NotificationIndexes()
private init() {
@ -890,7 +891,29 @@ final class TerminalNotificationStore: ObservableObject {
focusedReadIndicatorByTabId[tabId]
}
func addNotification(tabId: UUID, surfaceId: UUID?, title: String, subtitle: String, body: String) {
func addNotification(
tabId: UUID,
surfaceId: UUID?,
title: String,
subtitle: String,
body: String,
cooldownKey: String? = nil,
cooldownInterval: TimeInterval? = nil
) {
let now = Date()
let resolvedCooldownInterval: TimeInterval?
if let cooldownInterval, cooldownInterval.isFinite, cooldownInterval > 0 {
resolvedCooldownInterval = cooldownInterval
} else {
resolvedCooldownInterval = nil
}
if let cooldownKey,
let resolvedCooldownInterval,
let lastNotificationDate = lastNotificationDateByCooldownKey[cooldownKey],
now.timeIntervalSince(lastNotificationDate) < resolvedCooldownInterval {
return
}
var updated = notifications
var idsToClear: [String] = []
updated.removeAll { existing in
@ -925,11 +948,14 @@ final class TerminalNotificationStore: ObservableObject {
title: title,
subtitle: subtitle,
body: body,
createdAt: Date(),
createdAt: now,
isRead: false
)
updated.insert(notification, at: 0)
notifications = updated
if let cooldownKey, resolvedCooldownInterval != nil {
lastNotificationDateByCooldownKey[cooldownKey] = now
}
if !idsToClear.isEmpty {
center.removeDeliveredNotificationsOffMain(withIdentifiers: idsToClear)
center.removePendingNotificationRequestsOffMain(withIdentifiers: idsToClear)