Skip to content

fix(flags): treat concurrent fallback-cache eviction as a cache miss - #1167

Merged
marandaneto merged 2 commits into
PostHog:mainfrom
Sarbajit-Sengupta:fix/cache-eviction-reads
Nov 2, 2026
Merged

marandaneto merged 2 commits into
PostHog:mainfrom
Sarbajit-Sengupta:fix/cache-eviction-reads

Conversation

@Sarbajit-Sengupta

@Sarbajit-Sengupta Sarbajit-Sengupta commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Motivation and context

The in-memory fallback cache checks membership and then indexes the same dictionaries. A concurrent eviction, clear or invalidation can remove a user or flag between those operations, raising KeyError. The stale read is used from the public flag lookup's request-error handlers, so a cache eviction during an outage can itself escape to application code.

Read each dictionary entry with get() and keep that result locally. An entry removed before its lookup is an ordinary miss. This retains generation, TTL, stale-age and result checks without adding a blocking cache lock or changing public API. It is a narrow lookup-race fix, not a claim that every cache operation is now thread-safe.

How tested

  • Six deterministic regression cases fail on unchanged upstream and pass with the fix: user eviction and flag removal on fresh/stale reads, plus public get_feature_flag_result() calls during a simulated connection outage.
  • A separate native-dictionary threading probe with forced yields between reader statements produced 714 KeyErrors before / zero after (four readers, 30,000 iterations each). The injected yields deliberately exercise the race; these counts are not a production failure-rate claim.
  • Utility, cache-publication, Redis-snapshot and new regression suites: 179 passed, 2 skipped on Windows / Python 3.13, with loopback access enabled.
  • Whole-repository Ruff formatting and lint checks passed; the prescribed mypy/baseline pipeline passed for 326 source files; warning-as-error import and diff checks passed.
  • The broader SDK run reached 2,750 passed, 26 skipped, 18 subtests passed, then stopped at TestClient.test_basic_capture_exception_with_no_exception_given, whose filename assertion expects / while Windows emits \\. The same test fails on unchanged upstream code. A complete green full-suite run is not claimed.

Checklist

  • All commits are signed (GitHub reports a valid signature).
  • I reviewed the submitted code. (Automated review performed; independent human review is not claimed.)
  • I added tests to verify the changes.
  • No public API signature or documentation change is needed.

Agent context

Autonomy: Human-driven (agent-assisted). The account owner requested tested open-source contributions; the agent selected this defect, implemented it and performed the validation above. The human DRI is @Sarbajit-Sengupta. Assignment to that account was requested when creating the PR, but GitHub denied ReplaceActorsForAssignable; a maintainer needs to apply the assignee.

OpenAI Codex desktop, Python/pytest, Ruff, mypy, Git and GitHub CLI were used. The model is a GPT-6-based coding agent; an exact deployment variant is unavailable. A public session link is omitted because the conversation includes private account/workspace context. This description is not a claim of human production experience, independent human code review, a live-provider test or guaranteed delivery during outages. Human maintainer review is required; no self-merge is requested.

@Sarbajit-Sengupta
Sarbajit-Sengupta requested a review from a team as a code owner November 1, 2026 11:11

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good; no qualifying findings. Verdict: correct.

@marandaneto

Copy link
Copy Markdown
Member

thanks @Sarbajit-Sengupta

@marandaneto
marandaneto enabled auto-merge (squash) November 2, 2026 15:46
@marandaneto
marandaneto merged commit 9ebfb87 into PostHog:main Nov 2, 2026
42 checks passed
eli-r-ph added a commit that referenced this pull request Nov 4, 2026
* docs(mcp): clarify unsigned session token trust (#1151)

(cherry picked from commit b4c2e47)

* feat: send a flat body from emails.send (#1155)

emails.send now posts template_id and distinct_id at the top level of the request body, for the sync and async clients. The server accepts both shapes, so this changes only the wire format.

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

Generated-By: PostHog Desktop
Task-Id: e72a2c10-f145-4f7c-8754-a4fcc06a18be
(cherry picked from commit f20066e)

* chore: Release v7.81.2 [skip ci]

(cherry picked from commit 0aec2d9)

* Update generated references

(cherry picked from commit 14b4d33)

* feat: add a per-read send_feature_flag_events option to snapshot reads (#1148)

(cherry picked from commit b10c38a)

* fix: send flag id and version on locally evaluated $feature_flag_called (#1149)

Locally evaluated flags in get_feature_flag(), feature_enabled() and
get_feature_flag_result() sent $feature_flag_called without
$feature_flag_id or $feature_flag_version, because both were read only
from remote /flags metadata. Read them from the local flag definition
that produced the value. evaluate_flags() already sent the id for local
flags but dropped the definition's version; send it too.

(cherry picked from commit e24100b)

* chore: Release v7.82.0 [skip ci]

(cherry picked from commit b6f8eaf)

* Update generated references

(cherry picked from commit 0a5417f)

* fix(flags): treat concurrent fallback-cache eviction as a cache miss (#1167)

* fix(flags): treat concurrent cache eviction as a cache miss

* chore: add changeset for fallback cache eviction fix

---------

Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit 9ebfb87)

* fix(flags): stringify regex properties as compact JSON (#1157)

Local regex and not_regex matching called str() on the property.

(cherry picked from commit 5b50683)

* fix(flags): serialize UUID values in flags request bodies (#1156)

The flags request body goes straight to DatetimeSerializer without clean(), so a UUID distinct id, group key, or flag property raised TypeError. The SDK swallowed it and returned missing flags without sending a request. Serialize UUIDs as strings, matching what clean() already does for captured events.

(cherry picked from commit a239479)

* chore: Release v7.82.1 [skip ci]

(cherry picked from commit 8c5e9df)

* Update generated references

(cherry picked from commit fbbd109)

* fix(ai): count Gemini tool use prompt tokens as input tokens (#1164)

* fix(ai): count Gemini tool use prompt tokens as input tokens

Built-in tools (Google Search, URL context) report the retrieved content in
tool_use_prompt_token_count, separately from prompt_token_count, so input
tokens were under-reported on grounded responses.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Alex Castillo <alex.castillog33@gmail.com>

* chore: add changeset for Gemini tool use prompt tokens

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Alex Castillo <alex.castillog33@gmail.com>

* fix(ai): keep unbilled Google Search retrieval out of Gemini input tokens

tool_use_prompt_token_count is only added to input tokens when the response
carries url_context_metadata (billed as input); Search retrieval is not.

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

* fix(ai): carry Gemini URL context flag across stream chunks

URL context metadata can arrive on a different chunk than the final
usage_metadata, so the tool-use prompt tokens were dropped in streaming.
Track the flag across chunks in the sync and async clients.

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

* fix(ci): format Gemini clients and refresh API snapshot

---------

Signed-off-by: Alex Castillo <alex.castillog33@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
(cherry picked from commit 57b9db8)

* chore: Release v7.82.2 [skip ci]

(cherry picked from commit 16e99f0)

* Update generated references

(cherry picked from commit 1dfca27)

---------

Signed-off-by: Alex Castillo <alex.castillog33@gmail.com>
Co-authored-by: Dustin Byrne <dustin@posthog.com>
Co-authored-by: Harley Alexander <43975092+mayteio@users.noreply.github.com>
Co-authored-by: releaser-posthog-python[bot] <262414804+releaser-posthog-python[bot]@users.noreply.github.com>
Co-authored-by: Anders <754494+andehen@users.noreply.github.com>
Co-authored-by: Sarbajit Sengupta <73594751+Sarbajit-Sengupta@users.noreply.github.com>
Co-authored-by: Manoel Aranda Neto <marandaneto@gmail.com>
Co-authored-by: Luan Taraschi <130802253+luantaraschi@users.noreply.github.com>
Co-authored-by: alexcastgonz <82875882+pcbeingused333@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
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