Skip to content

Refresh a wallet's token once when two jobs find it expired together - #92

Merged
kev1n merged 1 commit into
mainfrom
alert-count-and-lead-quality
Sep 20, 2026
Merged

kev1n merged 1 commit into
mainfrom
alert-count-and-lead-quality

Conversation

@kev1n

@kev1n kev1n commented Sep 20, 2026

Copy link
Copy Markdown
Member

Why

One connected-wallet user (Chesspoly, We Want To Rent for tenants / for agents) has had every scan, competitor_scan and profile_reseed fail since 2026-09-19 18:16 with AnyAPI token request failed with status 400: 57 failures. They connected at 17:02; at 18:15, as the first access token expired, two of their scans ran in the same minute and both called refreshTokens with the same stored refresh token. AnyAPI rotates refresh tokens, so the second use reads as replay and the connection is revoked. Every other wallet user has one project, or was lucky.

What

walletAccessToken takes select … for update on the user's wallet_connections row before refreshing and re-checks freshness under the lock, so concurrent callers spend the refresh token once and the rest read the stored access token.

Testing

tests/walletRefresh.test.ts runs two clientForUser calls together against Postgres: 2 refreshes before the change, 1 after. Typecheck and lint clean; the only suite failure is the existing tests/jobs.test.ts timeout.

This does not revive the already-revoked connection; that user has to reconnect.

🤖 Generated with Claude Code

AnyAPI rotates the refresh token on every use and revokes the connection when
an old one is presented again. One user's three projects scanned in the same
minute, both scans found the hour-old access token expired, and both spent the
stored refresh token. The connection was revoked, and every job for that user
has failed with a 400 from the token endpoint since: 57 in a day.

The refresh now runs under a row lock on the wallet connection, and whoever
waited reads the token the first one stored.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@kev1n
kev1n merged commit cd53087 into main Sep 20, 2026
1 check passed
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