eschutho opened a new pull request, #44662:
URL: https://github.com/apache/superset/pull/44662

   ### SUMMARY
   
   Superset keeps query results in a "data cache" (usually Redis or Memcached) 
so repeat loads are fast. A single very large result, tens of megabytes, can 
fill that cache's memory and push out many smaller, useful entries. Superset 
already had a setting to stop this, `DATA_CACHE_MAX_VALUE_SIZE`: a cap on how 
big one cached value may be. It was off by default, and some code paths that 
write to the data cache ignored it.
   
   This PR:
   
   1. **Turns the cap on by default at 10 MB.** A value larger than 10 MB is 
not stored. The request still returns its data, but the next load re-runs the 
query because nothing was cached. Each skipped write logs a WARNING that names 
the cache key and the size, and increments the `skip_cache_value_too_large` 
statsd counter. Operators can raise the cap or set it to `None` to turn it off.
   
   2. **Applies the cap to every writer to the data cache.** The size check 
moves into a small shared helper, `exceeds_max_cache_value_size()` in 
`superset/utils/cache.py`. The normal chart path (`set_and_log_cache`) uses it, 
and so do three places that wrote to the cache directly and skipped the check:
      - the SQL executor's result cache (`superset/sql/execution/executor.py`)
      - the column-values endpoint that fills filter dropdowns 
(`superset/datasource/api.py`)
      - the compatible metrics/dimensions endpoint 
(`superset/datasource/api.py`)
   
      In all three, a skipped write is just a cache miss: the next request runs 
the query again. Nothing reads the value back expecting it to be there, so 
skipping can't cause a loop or an error.
   
   3. **Fixes an endless retry with async chart queries.** With 
`GLOBAL_ASYNC_QUERIES` on, a background worker runs the chart query and stores 
the result in the data cache. The browser then asks for the chart again and 
expects to read that stored result. If the result was too big to store, the 
browser's read misses, the server treats that as "not ready yet", and a new 
background job starts, again and again. With this change the worker checks that 
the result really landed in the cache. If it didn't, the job fails with a clear 
message ("The query result could not be cached and cannot be returned 
asynchronously... exceeds DATA_CACHE_MAX_VALUE_SIZE..."), so the user sees an 
error instead of a chart that never finishes loading.
   
   4. **Docs.** Updates the config comment, the caching docs page, and 
`UPDATING.md`. Also rewrites a code comment in `superset/utils/cache.py` that 
still called `None` the default.
   
   A timeout of `0` ("never expire") behaves as before.
   
   ### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
   
   Not applicable (no UI change). With async queries on, an oversized chart 
result now shows an error instead of loading forever.
   
   ### TESTING INSTRUCTIONS
   
   Unit tests:
   
   ```
   pytest tests/unit_tests/utils/cache_test.py \
          tests/unit_tests/tasks/test_async_queries.py \
          tests/unit_tests/sql/execution/test_executor.py \
          tests/unit_tests/datasource/cache_size_cap_test.py
   ```
   
   What they cover:
   - The default cap is set. A normal-size value is cached with the real 
default, and a value over the default is skipped with a WARNING and the counter.
   - Boundary: a value exactly at the cap is cached, and one byte over is 
skipped.
   - With the cap set to `None`, values aren't even serialized to measure them.
   - An explicit cache timeout is passed through unchanged, and a timeout of 
`0` is still honored.
   - Async: when the query succeeds but its result isn't in the cache, the task 
raises and never reports a cache key the client would retry against.
   - The SQL executor, column-values endpoint, and compatible endpoint each 
skip an oversized value (still returning it to the caller) and cache a normal 
one.
   
   Manual check (optional):
   1. Configure a real data cache (e.g. Redis) and set 
`DATA_CACHE_MAX_VALUE_SIZE = 1024` in `superset_config.py`.
   2. Load a chart that returns more than 1 KB of data. It still renders. The 
logs show `Skipping cache set for key ...`, and reloading re-runs the query.
   3. With `GLOBAL_ASYNC_QUERIES` on, load the same chart. It shows the "could 
not be cached" error rather than loading forever.
   
   ### ADDITIONAL INFORMATION
   - [ ] Has associated issue:
   - [ ] Required feature flags:
   - [ ] Changes UI
   - [ ] Includes DB Migration (follow approval process in 
[SIP-59](https://github.com/apache/superset/issues/13351))
     - [ ] Migration is atomic, supports rollback & is backwards-compatible
     - [ ] Confirm DB migration upgrade and downgrade tested
     - [ ] Runtime estimates and downtime expectations provided
   - [ ] Introduces new feature or API
   - [ ] Removes existing feature or API
   
   Behavior change for operators: the new 10 MB default means results over 10 
MB are no longer cached. See `UPDATING.md`.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to