Fix view count race conditions in TweetBlock#165
Merged
filinvadim merged 2 commits intodevelopfrom May 4, 2026
Merged
Conversation
Symptom: scrolling past a tweet flashed the new view count and then reverted to the previous lower number, so the UI looked like view tracking was off. Root cause: TweetBlock fires getTweetStats (loadTweetStats) and viewTweet (recordView) concurrently. When viewTweet's RecordView commits first but the parallel getTweetStats request had already read the pre-increment count, the stats response lands second with a smaller value and the unconditional viewsCount.set overwrites the just-incremented total. Fix: only update viewsCount when the incoming value is strictly greater than the current local value, in both loadTweetStats and recordView. View counts are monotonically non-decreasing under RecordView + CRDT, so taking the running max is safe and eliminates the race. Validated by a new TweetBlock spec that drives the IntersectionObserver, including a regression test for the loadTweetStats/recordView race.
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a race condition in the TweetBlock Vue component where concurrent loadTweetStats and recordView calls could overwrite the UI’s view count with stale/lower values, ensuring view counts are monotonically non-decreasing on the client.
Changes:
- Update
loadTweetStatsto only applyviews_countwhen it increases the current local value. - Update
recordViewto only apply the returned count when it is greater than the current local value. - Add a comprehensive Vitest suite covering visibility thresholds, deduplication, transient failure retry, and the
loadTweetStatsvsrecordViewrace.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
version |
Bumps application version to 0.6.306. |
frontend/src/components/TweetBlock.vue |
Enforces monotonic view-count updates across async races. |
frontend/tests/components/TweetBlock.spec.js |
Adds coverage for view tracking behavior and race scenarios. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -0,0 +1,270 @@ | |||
| import { describe, it, expect, beforeAll, afterAll, beforeEach, vi } from 'vitest'; | |||
| import { render, screen, waitFor } from '@testing-library/vue'; | |||
Comment on lines
+342
to
+343
| // loadTweetStats response lands after us, or when the backend | ||
| // reports 0 because the author's node is unreachable. |
- TweetBlock.spec.js: drop unused `screen` import. - TweetBlock.vue: simplify the recordView monotonic-update comment. The "0 because the author's node is unreachable" wording conflicted with viewTweet's documented contract (null = failure, numeric = backend-reported count). The race we actually guard against is the loadTweetStats response landing after us with a stale value, so keep that as the sole justification.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixed race conditions in the TweetBlock component where view counts could be incorrectly overwritten by stale data or regress to lower values. The component now maintains monotonically non-decreasing view counts across concurrent API calls.
Key Changes
count > 0tocount > currentto ensure the view count never regresses when the backend reports 0 or when a stale loadTweetStats response arrives after recordView completesImplementation Details
The fix ensures that view counts are monotonically non-decreasing by comparing incoming values against the current local state before updating. This handles two critical race scenarios:
Version bumped to 0.6.306.
https://claude.ai/code/session_01MABzdRsy5KrkRrWYSicHyq