Skip to content

Use a bounded LRU cache by default in ParserCache and ValidationCache - #4606

Merged
patrick91 merged 1 commit into
mainfrom
default/max
Aug 31, 2026
Merged

Use a bounded LRU cache by default in ParserCache and ValidationCache#4606
patrick91 merged 1 commit into
mainfrom
default/max

Conversation

@patrick91

@patrick91 patrick91 commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary by Sourcery

Bound parser and validation caches by default to protect publicly exposed servers from unbounded memory growth.

Bug Fixes:

  • Prevent unbounded memory growth from unique query texts by making ParserCache and ValidationCache bounded by default.

Enhancements:

  • Set both caches to a 128-entry least-recently-used limit by default while preserving explicitly configurable, including unbounded, cache sizes.

Documentation:

  • Document the new 128-entry defaults, eviction behavior, and risks of opting into unbounded caches.

Tests:

  • Add coverage verifying that both caches retain at most 128 entries by default.

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for adding the RELEASE.md file!

Below is the changelog that will be used for the release.


This release fixes a potential unbounded memory growth in the ParserCache and
ValidationCache extensions.

Both extensions previously defaulted to maxsize=None, which creates an
unbounded functools.lru_cache. On a network-exposed endpoint with one of these
extensions enabled, a client sending many distinct query texts could grow the
server's memory without limit.

The default is now a bounded LRU cache of 128 entries, matching the
functools.lru_cache default. Existing behavior can be restored by explicitly
opting in to an unbounded cache:

import strawberry
from strawberry.extensions import ParserCache, ValidationCache

schema = strawberry.Schema(
    Query,
    extensions=[
        ParserCache(maxsize=None),  # explicitly unbounded
        ValidationCache(maxsize=100),
    ],
)

Only use maxsize=None when the set of distinct query texts reaching the server
is trusted and bounded.

This release was contributed by @patrick91 in #4606

@patrick91
patrick91 enabled auto-merge (squash) August 31, 2026 22:19

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Approved.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@greptile-apps

greptile-apps Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR changes ParserCache and ValidationCache to use a bounded 128-entry LRU cache by default, preventing untrusted query text from causing unbounded memory growth. Explicit maxsize=None remains available for trusted, bounded workloads.

  • Adds a shared default cache-size constant to both extensions.
  • Updates extension documentation and release notes to explain bounded and unbounded configurations.
  • Adds tests confirming that default caches retain at most 128 entries.

Confidence Score: 5/5

The PR appears safe to merge and improves resilience against memory growth from unique client queries.

Both extensions now use the intended bounded default, preserve explicit unbounded configuration, and retain safe cache keys and existing extension lifecycle behavior.

Important Files Changed

Filename Overview
strawberry/extensions/parser_cache.py Changes the parser cache default from unbounded to a 128-entry shared LRU while preserving explicit unbounded configuration.
strawberry/extensions/validation_cache.py Changes the validation cache default to 128 entries; cache keys continue to include schema identity, document, and validation rules.
tests/schema/extensions/test_parser_cache.py Verifies the parser cache default and eviction bound using 200 distinct query texts.
tests/schema/extensions/test_validation_cache.py Verifies that schema validation through the default extension populates no more than 128 shared cache entries.
RELEASE.md Documents the resource-exhaustion motivation, compatibility impact, and explicit unbounded opt-in.
docs/extensions/parser-cache.md Updates the ParserCache API reference and explains when an unbounded cache is unsafe.
docs/extensions/validation-cache.md Updates the ValidationCache API reference and explains the bounded default.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[GraphQL request] --> B[Query text]
    B --> C{Parser cache hit?}
    C -->|Yes| D[Parsed document]
    C -->|No| E[Parse query]
    E --> F[Store in 128-entry LRU]
    F --> D
    D --> G{Validation cache hit?}
    G -->|Yes| H[Validation result]
    G -->|No| I[Validate against schema]
    I --> J[Store in 128-entry LRU]
    J --> H
    F -. least recently used eviction .-> K[Bounded memory]
    J -. least recently used eviction .-> K
Loading

Reviews (1): Last reviewed commit: "Use a bounded LRU cache by default in Pa..." | Re-trigger Greptile

@codspeed-hq

codspeed-hq Bot commented Aug 31, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 34 untouched benchmarks


Comparing default/max (03e4d9e) with main (2ebb797)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (7508b58) during the generation of this report, so 2ebb797 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@patrick91
patrick91 disabled auto-merge August 31, 2026 22:28
@patrick91
patrick91 merged commit 4837f62 into main Aug 31, 2026
86 checks passed
@patrick91
patrick91 deleted the default/max branch August 31, 2026 22:28
@botberry

Copy link
Copy Markdown
Member

This PR was published as 0.327.0. Thank you for contributing!

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