A release-readiness QA pass over the whole product. The commits split into defects a user would hit and gates that were reporting green while measuring nothing. ## Fixes that change behaviour Rate limiting was bypassable on every install: TRUST_PROXY defaulted to true, so request.ip came from a client-set header and a forged X-Forwarded-For got past the login limiter. The default is now a private-network trust list. A transient Postgres outage stranded in-flight jobs, leaving finished output on disk with no row pointing at it. A reconciler now resolves those rows and adopts the bytes rather than dropping the work. A Redis connection that moved to a new address wedged every read-blocked consumer, so completions stopped signalling while health still answered 200. Socket timeouts plus subscriber pings recover it. Installing more than one AI bundle left the shared venv multi-versioned and silently broke three tools. The installer now reconciles distributions to one version each. Converting an image to JXL at quality 1 through 4 returned a 500, because libjxl 0.7 rejects the distance those values compute. The quality is floored at what the encoder honours. A missing ffmpeg was also reported to the user as a corrupt upload; it now says the engine is unavailable. RAW uploads reached an unpatched LibRaw on arm64, so it is built from source at 0.22.2, and the release scan was split so it can fail on an unfixed critical instead of hiding it behind ignore-unfixed. ## Gates that could not fail Two mutation lanes ran zero mutants because Stryker crawled the gitignored docs build; coverage discarded its whole report on any failing test; the lint gate skipped root tests, scripts, and two workspaces; and several generated matrices counted a host missing ffmpeg as a passing tool. Each now measures what it claims. Full evidence and the outstanding release items are tracked locally and are not part of this branch.
7.2 KiB
i18n_source_hash, i18n_provenance, i18n_output_hash, i18n_hash_version
| i18n_source_hash | i18n_provenance | i18n_output_hash | i18n_hash_version |
|---|---|---|---|
| 521c03a6416c | machine | 6c00dd8cf948 | 2 |
Configurations à ressources limitées
SnapOtter tourne bien sur du petit matériel : un Raspberry Pi 4 ou 5, un vieux portable ou un VPS de 2 Go. Cette page est le guide pratique pour ces machines : à quoi s'attendre, une installation à copier-coller avec des plafonds raisonnables, et quelles fonctionnalités laisser de côté. Les données de benchmark complètes derrière ces chiffres se trouvent dans Exigences matérielles.
Deux contraintes strictes d'emblée :
- 64 bits uniquement. L'image est construite pour
linux/amd64etlinux/arm64. L'ARM 32 bits (armv7/armhf) n'est pas pris en charge : les Pi de première génération et la famille Pi Zero sont donc exclus. - Plancher mémoire de 2 Go. 512 Mo ne suffisent pas à démarrer la pile, et 1 Go échoue sur les lots multi-fichiers. 2 Go avec 2 cœurs est la plus petite configuration qui fonctionne confortablement.
Ce qui tourne bien sur du petit matériel
Tous les outils non-IA fonctionnent sur une machine à 2 Go / 2 cœurs : l'intégralité des sections Image et Fichiers, les outils PDF et les opérations vidéo et audio en copie de flux (couper, couper le son, changer de conteneur). La plupart se terminent en moins d'une seconde.
Deux charges de travail font exception :
- Le réencodage vidéo (conversion entre codecs) est limité par le CPU. Un clip 1080p qui prend ~40 s sur un CPU de bureau rapide peut prendre plusieurs minutes sur un CPU de classe Pi. Les opérations en copie de flux restent instantanées.
- Les outils IA demandent de la RAM (4 Go recommandés) et du disque (les bundles les plus gros font 4-5 Go chacun), et les plus lourds (mise à l'échelle, restauration de photos, suppression d'arrière-plan) ne sont pas utilisables en pratique sur des CPU de classe Pi. L'IA légère comme la détection de visages et l'OCR reste utilisable si vous avez la mémoire nécessaire.
Rien de tout cela n'est installé ni actif tant que vous ne l'utilisez pas : sans bundle IA installé, l'application tourne au repos autour de 360 Mo, et les bundles IA ne se téléchargent que lorsqu'un admin les active.
Pas à pas : Raspberry Pi / vieux portable
C'est l'installation Compose standard de Prise en main, plus des limites de ressources et des plafonds prudents. Elle suppose un OS 64 bits (sur un Pi : Raspberry Pi OS 64 bits ou Ubuntu Server arm64).
services:
snapotter:
image: snapotter/snapotter:latest
ports:
- "1349:1349"
volumes:
- ./snapotter-data:/data
environment:
- DATABASE_URL=postgres://snapotter:snapotter@db:5432/snapotter
- REDIS_URL=redis://redis:6379
# Small-box profile: see the table below for what each cap does.
- CONCURRENT_JOBS=1
- MAX_WORKER_THREADS=2
- MAX_BATCH_SIZE=5
- MAX_UPLOAD_SIZE_MB=100
- MAX_MEGAPIXELS=50
- MAX_VIDEO_DURATION_S=300
deploy:
resources:
limits:
cpus: "2"
memory: 2G
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:17-alpine
environment:
- POSTGRES_USER=snapotter
- POSTGRES_PASSWORD=snapotter # Changez ceci pour les déploiements non locaux
- POSTGRES_DB=snapotter
volumes:
- ./postgres-data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:8-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy noeviction
restart: unless-stopped
Remarques pour les machines de classe Pi :
- Préférez un SSD USB à une carte SD pour le volume de données et Postgres. Les espaces de travail des jobs font de vraies E/S disque, et les cartes SD sont à la fois lentes et vite usées.
- Le conteneur unique tout-en-un fonctionne aussi ici (PostgreSQL et Redis embarqués quand
DATABASE_URL/REDIS_URLne sont pas définis), et sur un hôte limité en mémoire, abaissez le plafond de son Redis embarqué avecREDIS_MAXMEMORY(voir Configuration). Compose vous donne un contrôle plus fin par service, c'est pourquoi ce pas à pas l'utilise. - Ajoutez du swap sur les appareils à 2 Go. Cela évite qu'un pic occasionnel (un gros PDF, un lot que vous avez oublié de plafonner) se termine en arrêt pour manque de mémoire. zram est l'option qui ménage les cartes SD.
- L'image arm64 est CPU uniquement ; il n'y a pas de CUDA sur les cartes ARM.
Les leviers de réglage
Tous les plafonds sont des variables d'environnement, documentées en détail dans Configuration. 0 signifie illimité ou automatique. Ceux qui comptent sur du petit matériel :
| Variable | Suggestion petite machine | Ce que ce plafond protège |
|---|---|---|
CONCURRENT_JOBS |
1 |
Combien de jobs s'exécutent en parallèle. L'auto-détection prend les cœurs CPU moins un : très bien sur une grosse machine, trop gourmand sur une machine à 2 cœurs sous pression mémoire. |
MAX_WORKER_THREADS |
2 |
Pool de threads du traitement d'image. |
MAX_BATCH_SIZE |
5 |
Les lots sont le premier endroit où les machines à 1-2 Go manquent de mémoire. |
MAX_UPLOAD_SIZE_MB |
100 |
Empêche un seul fichier énorme d'occuper tout l'espace de travail. |
MAX_MEGAPIXELS |
50 |
Décoder une image de plus de 100 MP coûte de la RAM, quelle que soit la taille du fichier. |
MAX_VIDEO_DURATION_S |
300 |
Les longs transcodages monopolisent un petit CPU pendant des minutes, voire des heures. |
PROCESSING_TIMEOUT_S |
600 |
Plafond dur pour qu'un job hors de contrôle finisse par libérer la machine. |
Ces plafonds s'appliquent à ce que le serveur accepte : réglez-les donc selon ce que vous utilisez réellement, pas au plus bas possible. Si vous ne touchez jamais à la vidéo, un plafond MAX_VIDEO_DURATION_S ne coûte rien ; si vous numérisez des documents tous les jours, ne plafonnez pas MAX_PDF_PAGES.
Ce qu'il faut laisser de côté
- Les bundles IA lourds. La mise à l'échelle, la restauration de photos et la suppression d'arrière-plan demandent un GPU ou un CPU rapide à nombreux cœurs, et chaque bundle coûte 4-5 Go de disque. Sur une petite machine, ne les installez tout simplement pas ; les outils dont le bundle manque affichent une invite d'installation au lieu de s'exécuter.
- Le réencodage vidéo comme charge de travail régulière. Des transcodages occasionnels ne posent pas de problème (ils sont juste lents) ; une file de transcodage continue demande des cœurs CPU, pas un Pi.
- Les outils inutilisés en général. Un admin peut désactiver des outils individuels dans les Paramètres, ce qui les retire de l'interface et cesse d'enregistrer leurs routes API. Cela ne libère pas de mémoire en soi, mais évite qu'une petite instance partagée serve précisément à la charge de travail que le matériel ne peut pas encaisser.
Si vous déplacez plus tard l'instance vers du matériel plus puissant, retirez les plafonds (remettez-les à 0) et le même volume de données suit tel quel.