Files
SnapOtter/apps/docs/uk/guide/low-resource.md
T
SnapOtterandGitHub d10d0f544f fix: release QA hardening across processing, media, security, and CI gates (#649)
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.
2026-07-27 15:37:30 +08:00

10 KiB
Raw Blame History

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), і той самий том даних переїде разом з ним.