feat: tighten desktop presence loop and refine admin-web UX
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m46s
Backend CI / Backend (push) Failing after 7m52s
Desktop Client Build / Build Desktop Client (push) Successful in 27m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 59s
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m46s
Backend CI / Backend (push) Failing after 7m52s
Desktop Client Build / Build Desktop Client (push) Successful in 27m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 59s
- Shrink desktop presence TTL to 30s and heartbeat to 15s so unexpected client exits surface within one TTL even if the explicit offline call is missed; keep migration default aligned. - Trust a known presence miss in resolveDesktopClientOnline instead of falling back to the recent-heartbeat heuristic, so a still-cached LastSeenAt cannot mask an offline client. - Release the runtime session before clearing renderer desktop sessions on shutdown to avoid leaving stale leases behind. - Auto-refresh the MediaView account list every 5s and revamp card layout (inline platform badge, status tags, UID row, meta box). - Let the brand-question AI wizard accept multiple seed topics via a tag-style input; candidates from each topic are merged and deduped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -656,8 +656,8 @@ func resolveDesktopClientOnline(
|
||||
if client == nil || client.RevokedAt != nil {
|
||||
return false
|
||||
}
|
||||
if presenceKnown && presence {
|
||||
return true
|
||||
if presenceKnown {
|
||||
return presence
|
||||
}
|
||||
if client.LastSeenAt == nil {
|
||||
return false
|
||||
|
||||
@@ -21,15 +21,27 @@ func TestResolveDesktopClientOnline_PresenceHitWins(t *testing.T) {
|
||||
assert.True(t, online)
|
||||
}
|
||||
|
||||
func TestResolveDesktopClientOnline_FallsBackToRecentHeartbeatWhenPresenceMisses(t *testing.T) {
|
||||
func TestResolveDesktopClientOnline_PresenceMissWithKnownPresenceIsOffline(t *testing.T) {
|
||||
now := time.Date(2026, 4, 19, 21, 30, 0, 0, time.UTC)
|
||||
lastSeen := now.Add(-30 * time.Second)
|
||||
lastSeen := now.Add(-desktopClientPresenceTTL / 2)
|
||||
|
||||
online := resolveDesktopClientOnline(&repository.DesktopClient{
|
||||
ID: uuid.New(),
|
||||
LastSeenAt: &lastSeen,
|
||||
}, false, true, now)
|
||||
|
||||
assert.False(t, online)
|
||||
}
|
||||
|
||||
func TestResolveDesktopClientOnline_FallsBackToRecentHeartbeatWhenPresenceUnknown(t *testing.T) {
|
||||
now := time.Date(2026, 4, 19, 21, 30, 0, 0, time.UTC)
|
||||
lastSeen := now.Add(-desktopClientPresenceTTL / 2)
|
||||
|
||||
online := resolveDesktopClientOnline(&repository.DesktopClient{
|
||||
ID: uuid.New(),
|
||||
LastSeenAt: &lastSeen,
|
||||
}, false, false, now)
|
||||
|
||||
assert.True(t, online)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
)
|
||||
|
||||
// desktopClientPresenceTTL is also used as the monitoring primary-client lease TTL.
|
||||
// Desktop heartbeat interval must stay below TTL/2, so one missed heartbeat does
|
||||
// not make another client eligible to steal a still-healthy primary lease.
|
||||
const desktopClientPresenceTTL = 90 * time.Second
|
||||
const desktopAccountPresenceTTL = 90 * time.Second
|
||||
// Desktop heartbeat interval is TTL/2, so unexpected client exits are reflected
|
||||
// as offline within one TTL even when the explicit offline request is missed.
|
||||
const desktopClientPresenceTTL = 30 * time.Second
|
||||
const desktopAccountPresenceTTL = 30 * time.Second
|
||||
|
||||
func desktopClientPresenceKey(clientID uuid.UUID) string {
|
||||
return "desktop:presence:client:" + clientID.String()
|
||||
|
||||
Reference in New Issue
Block a user