refactor(desktop): tighten account dedup, probe scheduling, and session cleanup
- Dedup AI platform accounts by platform ID rather than identity key, preferring higher health rank then newer verified_at - Clean up session data and health records when duplicate or replaced accounts are removed - Remove reconcileTrackedAccountRemoteState — no longer optimistically trust remote health state - Spread initial probes over a random window (5s–3min) to avoid thundering-herd on startup - Stop scheduling a next probe after an account is marked expired - Update AI platforms stats strip to show authorized/pending instead of configured/authorized Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,8 @@ import { getPersistedPartition, getSessionHandle } from './session-registry'
|
||||
|
||||
const PROBE_TICK_MS = 10_000
|
||||
const STALE_AFTER_MS = 45 * 60_000
|
||||
const INITIAL_PROBE_MIN_MS = 5_000
|
||||
const INITIAL_PROBE_MAX_MS = 3 * 60_000
|
||||
const REGULAR_PROBE_MIN_MS = 30 * 60_000
|
||||
const REGULAR_PROBE_MAX_MS = STALE_AFTER_MS
|
||||
const CONFIRM_BACKOFF_STEPS_MS = [30_000, 120_000] as const
|
||||
@@ -103,7 +105,7 @@ function resolveKnownPartition(accountId: string): string | null {
|
||||
}
|
||||
|
||||
function nextInitialProbeAt(now = Date.now()): number {
|
||||
return now
|
||||
return now + randomInt(INITIAL_PROBE_MIN_MS, INITIAL_PROBE_MAX_MS)
|
||||
}
|
||||
|
||||
function nextRegularProbeAt(now = Date.now()): number {
|
||||
@@ -311,7 +313,7 @@ function applyExpiredResult(
|
||||
record.probeState = 'idle'
|
||||
record.authReason = result.reason ?? 'login_redirect'
|
||||
record.lastProbeAt = now
|
||||
record.nextProbeAt = nextRegularProbeAt(now)
|
||||
record.nextProbeAt = null
|
||||
record.lastAuthFailureAt = now
|
||||
record.suspectedExpiredAt = null
|
||||
record.confirmFailureCount = 0
|
||||
@@ -795,58 +797,6 @@ export function markTrackedAccountMissingPartition(
|
||||
return snapshot
|
||||
}
|
||||
|
||||
export function reconcileTrackedAccountRemoteState(
|
||||
account: PublishAccountIdentity,
|
||||
input: {
|
||||
health?: DesktopAccountInfo['health'] | null
|
||||
verifiedAt?: string | null
|
||||
profile?: AccountHealthProfile | null
|
||||
},
|
||||
): AccountHealthSnapshot | null {
|
||||
if (input.health !== 'live') {
|
||||
return getAccountHealthSnapshot(account.id)
|
||||
}
|
||||
|
||||
const remoteVerifiedAt = parseVerifiedAt(input.verifiedAt)
|
||||
if (!remoteVerifiedAt) {
|
||||
return getAccountHealthSnapshot(account.id)
|
||||
}
|
||||
|
||||
const record = ensureRecord(account)
|
||||
const newestLocalStateAt = Math.max(
|
||||
record.lastVerifiedAt ?? 0,
|
||||
record.lastAuthFailureAt ?? 0,
|
||||
record.lastProbeAt ?? 0,
|
||||
)
|
||||
if (remoteVerifiedAt <= newestLocalStateAt) {
|
||||
return toPublicSnapshot(record)
|
||||
}
|
||||
|
||||
const previousSignature = snapshotSignature(record)
|
||||
record.authRevision += 1
|
||||
record.platform = account.platform
|
||||
record.authState = 'active'
|
||||
record.probeState = 'idle'
|
||||
record.authReason = 'bind_success'
|
||||
record.lastVerifiedAt = remoteVerifiedAt
|
||||
record.lastProbeAt = remoteVerifiedAt
|
||||
record.nextProbeAt = nextRegularProbeAt()
|
||||
record.lastAuthFailureAt = null
|
||||
record.profile = input.profile ?? record.profile
|
||||
record.sessionFingerprint = input.profile?.subjectUid ?? record.sessionFingerprint
|
||||
record.suspectedExpiredAt = null
|
||||
record.confirmFailureCount = 0
|
||||
|
||||
const snapshot = commitRecord(record, previousSignature)
|
||||
const queuedJob = probeJobs.get(account.id)
|
||||
if (queuedJob?.status === 'queued') {
|
||||
removeQueuedProbeJob(account.id)
|
||||
queuedJob.resolve(snapshot)
|
||||
}
|
||||
|
||||
return snapshot
|
||||
}
|
||||
|
||||
export function getAccountHealthSnapshot(accountId: string): AccountHealthSnapshot | null {
|
||||
ensureInitialized()
|
||||
const record = records.get(accountId)
|
||||
|
||||
Reference in New Issue
Block a user