Skip to content

Erase expired sessions with a background batch worker loop - #785

Draft
dowski wants to merge 1 commit into
dowski/session-helpersfrom
dowski/expired-session-cleanup
Draft

dowski wants to merge 1 commit into
dowski/session-helpersfrom
dowski/expired-session-cleanup

Conversation

@dowski

@dowski dowski commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

A session's row was only deleted when its expired refresh token was
presented again, so a session nobody came back to kept its row, which
getSession reads for liveness, and its token rows forever.

The core component now mounts @convex-dev/batch-worker and runs a loop
that scans the issued refresh tokens oldest first (a new by_state index)
and erases each session whose newest issued token is past the TTL. An
expired token that is not its session's newest is a sibling whose
response was lost, so only that token is erased. When nothing is expired,
the loop sleeps until the oldest issued token expires, for at most a day.

The loop has no caller to pass it the TTL, so sign-in and refresh store
the refresh-token TTL in a one-row ttlConfig table when it differs from
the stored one, and ping the loop on a change. Each run reads the stored
TTL, so a lowered or a raised TTL applies to every session. A new session
also pings the loop; a plain refresh doesn't, since it only pushes its
session's expiry later.

refresh still enforces expiry against the TTL of its own call: the loop
only removes rows of sessions that can no longer refresh, and it may lag.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

@vercel

vercel Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
auth-v2 Ready Ready Preview Oct 28, 2026 8:43pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
convex-auth-docs Ignored Ignored Oct 28, 2026 8:43pm UTC

Request Review

dowski commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

@pkg-pr-new

pkg-pr-new Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
npm i https://pkg.pr.new/@convex-dev/auth@785

commit: 37d0505

@dowski
dowski force-pushed the dowski/expired-session-cleanup branch from fad1b09 to bea4c24 Compare October 26, 2026 23:27
@dowski
dowski force-pushed the dowski/session-helpers branch from d9700da to 2df0640 Compare October 26, 2026 23:27
@dowski
dowski force-pushed the dowski/session-helpers branch from 2df0640 to b31e38f Compare October 26, 2026 23:44
@dowski
dowski force-pushed the dowski/expired-session-cleanup branch from bea4c24 to 1163bbc Compare October 26, 2026 23:44
@dowski
dowski force-pushed the dowski/session-helpers branch from b31e38f to ffe383c Compare October 26, 2026 23:54
@dowski
dowski force-pushed the dowski/expired-session-cleanup branch from 1163bbc to 62e5b0d Compare October 26, 2026 23:54
@dowski
dowski force-pushed the dowski/session-helpers branch from ffe383c to ccb9abb Compare October 27, 2026 14:51
@dowski
dowski force-pushed the dowski/expired-session-cleanup branch from 62e5b0d to fe36e11 Compare October 27, 2026 14:51
@dowski
dowski force-pushed the dowski/session-helpers branch from ccb9abb to 5a2e1cd Compare October 27, 2026 15:04
@dowski
dowski force-pushed the dowski/expired-session-cleanup branch from fe36e11 to fc0aa85 Compare October 27, 2026 15:04
@dowski
dowski force-pushed the dowski/session-helpers branch from 5a2e1cd to 30421d4 Compare October 28, 2026 18:49
@dowski
dowski force-pushed the dowski/expired-session-cleanup branch from fc0aa85 to 99bceed Compare October 28, 2026 18:49
A session's row was only deleted when its expired refresh token was
presented again, so a session nobody came back to kept its row, which
getSession reads for liveness, and its token rows forever.

The core component now mounts @convex-dev/batch-worker and runs a loop
that scans the issued refresh tokens oldest first (a new by_state index)
and erases each session whose newest issued token is past the TTL. An
expired token that is not its session's newest is a sibling whose
response was lost, so only that token is erased. When nothing is expired,
the loop sleeps until the oldest issued token expires, for at most a day.

The loop has no caller to pass it the TTL, so sign-in and refresh store
the refresh-token TTL in a one-row ttlConfig table when it differs from
the stored one, and ping the loop on a change. Each run reads the stored
TTL, so a lowered or a raised TTL applies to every session. A new session
also pings the loop; a plain refresh doesn't, since it only pushes its
session's expiry later.

refresh still enforces expiry against the TTL of its own call: the loop
only removes rows of sessions that can no longer refresh, and it may lag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview – auth-v2 — 37d05056 Deployed Oct 28, 2026 by vercel[bot]
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