Stream a large response with single-flight Redis chunk caching. ``source`` must be a callable returning a chunk iterator. Only the leader invokes it; concurrent followers replay chunks already written to Redis, so the expensive ``source`` runs at most once per ``cache_key``.
(
cache_key,
source,
*,
content_type="application/xml",
filename=None,
cache_ttl=DEFAULT_CACHE_TTL,
lock_ttl=DEFAULT_LOCK_TTL,
poll_interval=DEFAULT_POLL_INTERVAL,
max_follower_wait=DEFAULT_MAX_FOLLOWER_WAIT,
redis=None,
)
| 188 | |
| 189 | |
| 190 | def stream_cached_response( |
| 191 | cache_key, |
| 192 | source, |
| 193 | *, |
| 194 | content_type="application/xml", |
| 195 | filename=None, |
| 196 | cache_ttl=DEFAULT_CACHE_TTL, |
| 197 | lock_ttl=DEFAULT_LOCK_TTL, |
| 198 | poll_interval=DEFAULT_POLL_INTERVAL, |
| 199 | max_follower_wait=DEFAULT_MAX_FOLLOWER_WAIT, |
| 200 | redis=None, |
| 201 | ): |
| 202 | """ |
| 203 | Stream a large response with single-flight Redis chunk caching. |
| 204 | |
| 205 | ``source`` must be a callable returning a chunk iterator. Only the leader |
| 206 | invokes it; concurrent followers replay chunks already written to Redis, so |
| 207 | the expensive ``source`` runs at most once per ``cache_key``. |
| 208 | """ |
| 209 | if redis is None: |
| 210 | redis = _get_redis() |
| 211 | |
| 212 | if redis.get(_ready_key(cache_key)): |
| 213 | logger.debug("Serving response from chunk cache") |
| 214 | stream = _stream_ready(redis, cache_key) |
| 215 | else: |
| 216 | status = _get_status(redis, cache_key) |
| 217 | if status == STATUS_ERROR: |
| 218 | _clear_build_keys(redis, cache_key) |
| 219 | |
| 220 | if _try_acquire_lock(redis, cache_key, lock_ttl): |
| 221 | logger.debug("Building response (cache leader)") |
| 222 | stream = _stream_build(redis, cache_key, source, cache_ttl, lock_ttl) |
| 223 | else: |
| 224 | logger.debug("Following in-flight cache build") |
| 225 | stream = _stream_follow( |
| 226 | redis, |
| 227 | cache_key, |
| 228 | source, |
| 229 | cache_ttl, |
| 230 | lock_ttl, |
| 231 | poll_interval, |
| 232 | max_follower_wait, |
| 233 | ) |
| 234 | |
| 235 | response = StreamingHttpResponse(stream, content_type=content_type) |
| 236 | if filename: |
| 237 | response["Content-Disposition"] = f'attachment; filename="{filename}"' |
| 238 | response["Cache-Control"] = "no-cache" |
| 239 | return response |