Repository navigation
fix(events): stop serving stale cached polls to per-thread clients - #831
Merged
Merged
Conversation
GET /v1/events caches each answer for 1.5s by its exact parameters, and caches a shared empty page when the caller's cursor is the newest event seen. Posting an event only cleared those entries for a fixed set of workspace-wide filters, never for channel=, target= or conversation= polls, and never for the exact-parameter entry at all. Clients that re-poll a thread on each SSE signal were hit hardest: a non-message event in the thread made them cache an empty page at the current cursor, the agent's reply landed inside the TTL, and the poll triggered by the reply got the cached empty page. The reply only showed up once some later event caused another poll. Both cached answers now include the workspace's event-write generation, which poll_queries already bumps after every committed event write (it keys the stream-head cache the same way). A write therefore retires every cached poll for that workspace, whatever its filters, while identical polls between writes still share one database query.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ll-cache # Conflicts: # workspace/backend/app/routers/events.py
This branch was successfully deployed
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.
Problem
GET /v1/eventscaches each answer for 1.5s by its exact parameters, and caches a shared empty page when the caller's cursor equals the newest event seen for that filter. When an event is posted,_invalidate_poll_cacheonly clears those entries for a fixed list of workspace-wide filters. Polls scoped withchannel=,target=orconversation=were never cleared, and neither was the exact-parameter entry.Clients that re-poll a thread on each SSE signal (the mobile app) were hit hardest:
channel=<thread>&type=workspace.message&after=<cursor>, gets an empty page, and that page is cached.Fix
Both cached answers (the exact-parameter entry and the at-head empty page) now include the workspace's event-write generation.
poll_queriesalready bumps this generation after every committed event write and uses it to key the stream-head cache. So a write now retires every cached poll for its workspace, whatever the filters, and identical polls between writes still share one database query. A poll that read the old generation before the commit can only write under the old key, so it cannot bring back a stale page.poll_generation()is factored out ofstream_head()so both caches read the generation the same way. The existing enumerated invalidation is left as is.Tests
TestPollCacheFreshness(channel and target scopes): post, catch up (cached empty page), post a reply within the TTL, and the same poll must return the reply. Both cases fail ondevelopand pass with this change.developis the two new tests going from failing to passing. The other failures also happen ondevelopand need a local Postgres (push fanout and similar).