-
Notifications
You must be signed in to change notification settings - Fork 10.1k
fix: add cache headers for images #9560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: add cache headers for images #9560
Conversation
server.py
Outdated
elif 200 <= response.status < 300: | ||
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_DAY}") | ||
elif response.status == 301 or response.status == 308: | ||
# Permanent redirects - cache for 1 day | ||
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_DAY}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
elif 200 <= response.status < 300: | |
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_DAY}") | |
elif response.status == 301 or response.status == 308: | |
# Permanent redirects - cache for 1 day | |
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_DAY}") | |
elif 200 <= response.status < 300 or response.status == 301 or response.status == 308: | |
# Permanent redirects - cache for 1 day | |
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_DAY}") |
server.py
Outdated
if response.status == 304: | ||
# 304 Not Modified - don't set cache headers, inherit from original | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be an and response.status != 304
on line 70?
server.py
Outdated
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_DAY}") | ||
elif 300 <= response.status < 400: | ||
# Temporary redirects (302, 303, 307) and other 3xx - no cache | ||
response.headers.setdefault('Cache-Control', 'no-cache') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just know there's a way to unify this with line 58...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good instincts, as usual. I'm missing the pattern with line 58. Could you show me what you're seeing there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@web.middleware
async def cache_control(request: web.Request, handler: Callable[[web.Request], Awaitable[web.Response]]) -> web.Response:
response: web.Response = await handler(request)
if request.path.endswith('.js') or request.path.endswith('.css') or request.path.endswith('index.json'):
response.headers.setdefault('Cache-Control', 'no-cache')
elif request.path.lower().endswith(IMG_EXTENSIONS):
if response.status == 404:
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_HOUR}")
elif response.status in (200, 201, 202, 203, 204, 205, 206, 301, 308):
# Success responses and permanent redirects - cache for 1 day
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_DAY}")
elif response.status in (302, 303, 307):
# Temporary redirects - no cache
response.headers.setdefault('Cache-Control', 'no-cache')
# Note: 304 Not Modified falls through - no cache headers set
return response
Something like this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
response.headers.setdefault('Cache-Control', 'no-cache')
and
response.headers.setdefault('Cache-Control', 'no-cache')
I'd love for each version to occur exactly once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm gonna push back on that last one.
We have clearly defined rules for js
and css
and images.
I don't think it makes sense to commingle rules for assets. just so that we only set no-cache
once.
Better to optimize by asset type than by cache level here. Makes it easier to tweak just images as well.
with patch('app.frontend_management.FrontendManager'): | ||
with patch('utils.install_util.get_missing_requirements_message'): | ||
with patch('utils.install_util.requirements_path'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if this is better, but it's an option
with patch('app.frontend_management.FrontendManager'): | |
with patch('utils.install_util.get_missing_requirements_message'): | |
with patch('utils.install_util.requirements_path'): | |
with patch('app.frontend_management.FrontendManager'), patch('utils.install_util.get_missing_requirements_message'), patch('utils.install_util.requirements_path'): |
server.py
Outdated
response.headers.setdefault('Cache-Control', f"public, max-age={ONE_DAY}") | ||
elif 300 <= response.status < 400: | ||
# Temporary redirects (302, 303, 307) and other 3xx - no cache | ||
response.headers.setdefault('Cache-Control', 'no-cache') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
response.headers.setdefault('Cache-Control', 'no-cache')
and
response.headers.setdefault('Cache-Control', 'no-cache')
I'd love for each version to occur exactly once.
pytestmark = pytest.mark.asyncio # Apply asyncio mark to all tests | ||
|
||
# Mock the problematic imports before importing server | ||
with patch('app.frontend_management.FrontendManager'), patch('utils.install_util.get_missing_requirements_message'), patch('utils.install_util.requirements_path'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DrJKL this was a good call by you. much easier to read.
Hold up. Need to refactor the middleware so we don't get stuck in mock hell with pytorch. |
Prevents unnecessary repeated requests, especially for 404s
We can test the code without excessively mocking server dependencies
7f0e91e
to
7cd6891
Compare
if ( | ||
request.path.endswith(".js") | ||
or request.path.endswith(".css") | ||
or request.path.endswith("index.json") | ||
): | ||
response.headers.setdefault("Cache-Control", "no-cache") | ||
elif request.path.lower().endswith(IMG_EXTENSIONS): | ||
if response.status == 404: | ||
response.headers.setdefault("Cache-Control", f"public, max-age={ONE_HOUR}") | ||
elif response.status in (200, 201, 202, 203, 204, 205, 206, 301, 308): | ||
# Success responses and permanent redirects - cache for 1 day | ||
response.headers.setdefault("Cache-Control", f"public, max-age={ONE_DAY}") | ||
elif response.status in (302, 303, 307): | ||
# Temporary redirects - no cache | ||
response.headers.setdefault("Cache-Control", "no-cache") | ||
# Note: 304 Not Modified falls through - no cache headers set | ||
|
||
return response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talked about elsewhere: This is probably more flattenable.
server.py
Outdated
except (aiohttp.ClientError, aiohttp.ClientPayloadError, ConnectionResetError, BrokenPipeError, ConnectionError) as err: | ||
logging.warning("send error: {}".format(err)) | ||
|
||
@web.middleware |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line should be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. My bad.
Overview
Fixes Comfy-Org/ComfyUI_frontend#4438
Majority of discussion was in:
TL;DR: Add cache controls to store images for 1 day and only try to resolve missing images every 1 hour.
Problem
Review Points
max-age
values? One day for images and permanent redirects. One hour for image 404's.