Skip to content

fix(tokens): claim redis socket tokens atomically#6771

Draft
anxkhn wants to merge 2 commits into
reflex-dev:mainfrom
anxkhn:fix/atomic-redis-token-claim
Draft

fix(tokens): claim redis socket tokens atomically#6771
anxkhn wants to merge 2 commits into
reflex-dev:mainfrom
anxkhn:fix/atomic-redis-token-claim

Conversation

@anxkhn

@anxkhn anxkhn commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Description

RedisTokenManager.link_token_to_sid previously checked whether a token existed
before storing its socket record in a separate Redis command. Concurrent workers
could both observe an absent token and then associate it with different sockets,
allowing two connections to share the same client state.

This change claims each token with an atomic Redis SET using NX and the existing
expiration. A worker that loses the claim retries with a new UUID, while Redis
errors continue to use the local token-manager fallback.

The regression test coordinates two managers against shared Redis state and verifies
that only one keeps the requested token. It fails against the previous implementation
and passes with the atomic claim.

Testing

  • uv run pytest tests/units/utils/test_token_manager.py -q (28 passed, 4 skipped)
  • uv run pytest tests/units --cov --no-cov-on-fail --cov-report= (6625 passed,
    17 skipped, 78.04% coverage)
  • uv run ruff check .
  • uv run ruff format . --check
  • uv run pyright reflex tests (0 errors)
  • uv run towncrier check --config pyproject.toml --compare-with origin/main

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

@anxkhn
anxkhn requested a review from a team as a code owner July 15, 2026 05:48
@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 8 skipped benchmarks1


Comparing anxkhn:fix/atomic-redis-token-claim (3e0cf0f) with main (2edaf12)

Open in CodSpeed

Footnotes

  1. 8 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@greptile-apps

greptile-apps Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a race condition in RedisTokenManager.link_token_to_sid by replacing a non-atomic EXISTS + SET sequence with a single SET NX command, ensuring only one worker can claim a given token even under concurrent load.

  • Core fix: link_token_to_sid now issues SET key value EX ttl NX atomically; a worker that loses the claim generates a new UUID and retries up to 3 times before falling back to LocalTokenManager.
  • Fallback paths: both the exhausted-retry (else branch) and the exception handler correctly delegate to super().link_token_to_sid(), which populates the local dicts and returns the final token; return fallback_token or new_token then propagates the right value to the caller in all cases.
  • Tests: existing tests updated to mock set (NX) instead of exists; two new tests cover the 3-attempt exhaustion fallback and the atomic-claim contract.

Confidence Score: 5/5

Safe to merge — the change is a well-scoped, targeted fix to a real concurrency bug in the Redis token-claim path with no regressions to the local fallback or disconnect logic.

The atomic SET NX approach is the standard Redis idiom for this pattern and is applied correctly. All three exit paths from link_token_to_sid (success, exhausted retries, exception) propagate the correct token and populate local dicts through the inherited LocalTokenManager. The retry cap of 3 is a meaningful improvement over the previously unbounded concern. Tests cover success, duplicate-detected, error, exhausted-retry, and the NX-wins-first-caller contract.

No files require special attention.

Important Files Changed

Filename Overview
reflex/utils/token_manager.py Replaces check-then-set with atomic SET NX; retry loop is capped at 3 attempts with a correct for/else fallback. Logic is sound and handles exception, exhausted-retry, and success paths correctly.
tests/units/utils/test_token_manager.py Tests updated to match new NX semantics; two new tests added for exhausted-retry fallback and the atomic-claim contract. All assertions trace correctly through the new code paths.
news/6771.bugfix.md Changelog entry accurately describes the fix.

Reviews (3): Last reviewed commit: "fix(tokens): address atomic claim review" | Re-trigger Greptile

Comment thread tests/units/utils/test_token_manager.py Outdated
Comment thread reflex/utils/token_manager.py Outdated
@Alek99 Alek99 closed this Jul 15, 2026
@Alek99

Alek99 commented Jul 15, 2026

Copy link
Copy Markdown
Member

Hi appreciate the contributions but can you prioritize Github issue also please address the AI review before marking it out of draft

@Alek99 Alek99 reopened this Jul 15, 2026
anxkhn added 2 commits July 17, 2026 20:57
Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
@anxkhn
anxkhn marked this pull request as draft July 17, 2026 16:34
@anxkhn
anxkhn force-pushed the fix/atomic-redis-token-claim branch from 553fbf1 to 3e0cf0f Compare July 17, 2026 16:34
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.

2 participants