perf(thumbs): pool NC client, smaller grid thumbs, eager owner load
Five stacked optimisations for the thumbnail hot path so the timeline grid lands in fewer round trips and fewer bytes. 1. PhotoThumbnail: switch from 'medium' (640px) to 'small' (240px) for grid cells. 240px oversamples 150-200px logical cells on 2x retina and drops payload 5-8x. Lightbox and preview filmstrip keep 'large' and 'medium' respectively. 2. nextcloud_dav: pool the httpx client. A module-level AsyncClient with HTTP/2 + keepalive (max_connections=64, keepalive_expiry=120s) replaces the per-request constructor that paid a fresh TCP+TLS handshake on every preview fetch. Auth is per-user so it stays at the call site via auth=BasicAuth(...). Lifespan-managed: init in main.py's lifespan startup, aclose on shutdown. requirements.txt gains the http2 extra to pull in h2 (not currently installed). Same change applies to fetch_memories_info_async since it hits the same host. 3. PhotoThumbnail img: add decoding="async" so JPEG/WebP decode moves off the main thread, plus fetchPriority="low" so grid backfill doesn't fight UI fetches. 4. Eager-load Photo.user via joinedload from the thumb handler. _get_photo_with_share_fallback gains an options parameter so other callers stay zero-overhead; only the thumb handler asks for the owner join. Eliminates the second SELECT users per request. 5. Disk-fallback path picks up Cache-Control: private, max-age=86400 in both the FileResponse and X-Accel branches so re-renders match the NC primary path's caching behaviour. Net: a warm grid page should drop from ~200-400 ms median per thumb to well under 100 ms; payload drops ~5-8x; backend sustains higher concurrency with fewer sockets to Nextcloud and one fewer Postgres round-trip per request.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
Photo model definition
|
||||
"""
|
||||
from sqlalchemy import Column, String, Integer, Float, Boolean, DateTime, ForeignKey, Text, Index
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
@@ -10,12 +11,17 @@ from app.database import Base
|
||||
|
||||
class Photo(Base):
|
||||
__tablename__ = 'photos'
|
||||
|
||||
|
||||
# Primary key
|
||||
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
|
||||
|
||||
# Owner
|
||||
user_id = Column(String, ForeignKey('users.id'), nullable=True, index=True)
|
||||
# Eager-loadable owner relationship. Used by the thumbnail handler so
|
||||
# one photo lookup also yields the NC creds we need to call the
|
||||
# preview endpoint, instead of issuing a second SELECT users WHERE
|
||||
# id=…. No FK change — user_id above already exists.
|
||||
user = relationship("User", lazy="select")
|
||||
|
||||
# File information
|
||||
filepath = Column(String, unique=True, nullable=False)
|
||||
|
||||
Reference in New Issue
Block a user