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.
10 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 | e8532c6c8a52 | 2 |
Робота на слабкому обладнанні
SnapOtter добре працює на скромному обладнанні: Raspberry Pi 4 чи 5, старому ноутбуці або VPS із 2 GB пам'яті. Ця сторінка є практичним посібником для таких машин: чого очікувати, готове до копіювання налаштування з розумними лімітами й які функції варто пропустити. Повні дані бенчмарків, на яких ґрунтуються ці цифри, наведено в розділі Вимоги до апаратного забезпечення.
Два жорсткі обмеження одразу:
- Тільки 64-бітні системи. Образ збирається для
linux/amd64іlinux/arm64. 32-бітний ARM (armv7/armhf) не підтримується, тож Pi першого покоління та сімейство Pi Zero відпадають. - Мінімум 2 GB пам'яті. 512 MB не запустять стек, а 1 GB не витримує пакетів із кількох файлів. Найменша конфігурація, що працює комфортно: 2 GB і 2 ядра.
Що добре працює на слабкому обладнанні
Кожен інструмент без AI працює на машині з 2 GB і 2 ядрами: цілі розділи «Зображення» та «Файли», PDF-інструменти, а також відео- та аудіооперації з копіюванням потоку (обрізання, вимкнення звуку, зміна контейнера). Більшість завершується менш ніж за секунду.
Винятками є два типи навантаження:
- Перекодування відео (конвертація між кодеками) обмежене процесором. Кліп 1080p, який на швидкому десктопному CPU займає ~40 с, на процесорі класу Pi може тривати кілька хвилин. Операції з копіюванням потоку залишаються миттєвими.
- AI-інструменти потребують RAM (рекомендовано 4 GB) і диска (більші бандли займають по 4-5 GB кожен), а важкі з них (масштабування, відновлення фото, видалення фону) непрактичні на процесорах класу Pi. Легкий AI, як-от виявлення облич і OCR, цілком придатний, якщо вистачає пам'яті.
Жодне з цих навантажень не встановлюється й не запускається, доки ви ним не користуєтеся: без встановлених AI-бандлів застосунок у простої займає близько 360 MB, а AI-бандли завантажуються лише тоді, коли адміністратор їх вмикає.
Покрокове налаштування Raspberry Pi / старого ноутбука
Це стандартне встановлення через Compose зі сторінки Початок роботи, плюс ліміти ресурсів і консервативні обмеження. Передбачається 64-бітна ОС (на Pi: Raspberry Pi OS 64-bit або 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 # Змініть це для нелокальних розгортань
- 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
Нотатки для машин класу Pi:
- Віддавайте перевагу USB SSD, а не SD-карті для тому даних і Postgres. Робочі простори завдань створюють реальне дискове навантаження, а SD-карти водночас повільні й швидко зношуються.
- Універсальний єдиний контейнер тут теж працює (вбудовані Postgres і Redis, коли
DATABASE_URL/REDIS_URLне встановлені), і на хості з обмеженою пам'яттю варто зменшити ліміт вбудованого Redis черезREDIS_MAXMEMORY(див. Конфігурація). Compose дає точніший контроль на рівні окремих сервісів, саме тому цей посібник використовує його. - Додайте swap на пристроях із 2 GB. Це вбереже від того, щоб випадковий сплеск (великий PDF, пакет, який ви забули обмежити) закінчився аварійним завершенням через брак пам'яті. Для SD-карт найдружніший варіант: zram.
- Образ arm64 працює лише на CPU; CUDA на платах ARM немає.
Параметри тонкого налаштування
Усі ліміти задаються змінними середовища й повністю задокументовані на сторінці Конфігурація. 0 означає «без обмежень» або «авто». Ось ті, що мають значення на слабкому обладнанні:
| Змінна | Порада для слабкої машини | Що вона захищає |
|---|---|---|
CONCURRENT_JOBS |
1 |
Скільки завдань виконується паралельно. Автовизначення бере кількість ядер CPU мінус одне: це нормально для потужних машин і занадто агресивно для 2-ядерної під тиском пам'яті. |
MAX_WORKER_THREADS |
2 |
Пул потоків обробки зображень. |
MAX_BATCH_SIZE |
5 |
Саме на пакетах машини з 1-2 GB найпершими вичерпують пам'ять. |
MAX_UPLOAD_SIZE_MB |
100 |
Не дає одному величезному файлу зайняти весь робочий простір. |
MAX_MEGAPIXELS |
50 |
Декодування зображення на понад 100 мегапікселів коштує RAM незалежно від розміру файлу. |
MAX_VIDEO_DURATION_S |
300 |
Тривалі перекодування монополізують слабкий CPU на хвилини, а то й години. |
PROCESSING_TIMEOUT_S |
600 |
Жорстка стеля, щоб завдання, яке вийшло з-під контролю, зрештою звільнило машину. |
Ці ліміти визначають, що сервер приймає, тож встановлюйте їх відповідно до того, чим ви реально користуєтеся, а не якомога меншими. Якщо ви ніколи не працюєте з відео, ліміт MAX_VIDEO_DURATION_S нічого не коштує; якщо ви щодня скануєте документи, не обмежуйте MAX_PDF_PAGES.
Що варто пропустити
- Важкі AI-бандли. Масштабування, відновлення фото й видалення фону потребують GPU або швидкого багатоядерного CPU, а кожен бандл займає 4-5 GB диска. На слабкій машині просто не встановлюйте їх; інструменти, чий бандл відсутній, показують запит на встановлення замість запуску.
- Перекодування відео як регулярне навантаження. Поодинокі перекодування цілком прийнятні (вони просто повільні); постійна черга перекодувань потребує ядер CPU, а не Pi.
- Загалом невикористовувані інструменти. Адміністратор може вимкнути окремі інструменти в Settings, що прибирає їх з інтерфейсу та припиняє реєстрацію їхніх API-маршрутів. Саме по собі це не економить пам'ять, але не дає використовувати спільний невеликий екземпляр для того єдиного навантаження, якого обладнання не витримує.
Якщо згодом ви перенесете екземпляр на потужніше обладнання, приберіть ліміти (поверніть їх до 0), і той самий том даних переїде разом з ним.