oedb-backend/oedb/middleware/cache.py

98 lines
No EOL
3.3 KiB
Python

"""
Caching middleware for the OpenEventDatabase.
"""
from oedb.utils.logging import logger
class CacheMiddleware:
"""
Middleware that adds caching headers to responses.
This middleware adds appropriate Cache-Control headers to responses
based on the endpoint and request method. It helps reduce server load
by allowing clients to cache responses for a specified period.
"""
def __init__(self, default_max_age=60):
"""
Initialize the middleware with default caching settings.
Args:
default_max_age: Default max-age in seconds for cacheable responses.
"""
self.default_max_age = default_max_age
# Define caching rules for different endpoints
# Format: (endpoint_prefix, method, max_age)
self.caching_rules = [
# Cache GET requests to /event for 60 seconds
('/event', 'GET', 60),
# Cache GET requests to /stats for 300 seconds (5 minutes)
('/stats', 'GET', 300),
# Cache GET requests to /demo for 3600 seconds (1 hour)
('/demo', 'GET', 3600),
# Don't cache search results
('/event/search', 'POST', 0),
]
def process_response(self, req, resp, resource, params):
"""
Add caching headers to the response.
Args:
req: The request object.
resp: The response object.
resource: The resource object.
params: The request parameters.
"""
# Don't add caching headers for error responses
if resp.status_code >= 400:
self._add_no_cache_headers(resp)
return
# Check if the request matches any caching rules
max_age = self._get_max_age(req)
if max_age > 0:
# Add caching headers
logger.debug(f"Adding caching headers with max-age={max_age} to {req.method} {req.path}")
resp.set_header('Cache-Control', f'public, max-age={max_age}')
resp.set_header('Vary', 'Accept-Encoding')
else:
# Add no-cache headers
self._add_no_cache_headers(resp)
def _get_max_age(self, req):
"""
Determine the max-age value for the current request.
Args:
req: The request object.
Returns:
int: The max-age value in seconds, or 0 for no caching.
"""
# Check if the request matches any caching rules
for endpoint, method, max_age in self.caching_rules:
if req.path.startswith(endpoint) and req.method == method:
return max_age
# Default: no caching for write operations, default max-age for read operations
if req.method in ('POST', 'PUT', 'DELETE', 'PATCH'):
return 0
elif req.method == 'GET':
return self.default_max_age
else:
return 0
def _add_no_cache_headers(self, resp):
"""
Add headers to prevent caching.
Args:
resp: The response object.
"""
logger.debug("Adding no-cache headers to response")
resp.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
resp.set_header('Pragma', 'no-cache')
resp.set_header('Expires', '0')