Skip to content

Управляемые скачивания ​

Реализовано 2026-09-24. Клиентская очередь в portable SDK и web-консоли дополняет серверные admission/bandwidth механизмы. HTTP-контракт не меняется; миграция БД не требуется. Решение: ADR 0022.

Что может пользователь ​

Экран «Скачивания / Downloads» показывает реальные и восстановленные задания текущей вкладки: ожидание, скачивание, задержку перед сетевым повтором, сохранение частичной копии, паузу, финальное сохранение, отмену, успех или ошибку. Счётчик байтов отражает записи во временную копию, а не подтверждение готовности итогового файла.

  • «Пауза» прерывает fetch/ожидание retry, закрывает временную запись и сохраняет завершённые блоки. Слот освобождается после окончания этих операций.
  • «Продолжить / повторить» перечитывает и хеширует сохранённый префикс, затем скачивает суффикс через Range/If-Range. Задание становится в конец очереди. Ошибка не создаёт бесконечных автоматических перезапусков.
  • «Отменить» останавливает выбранное задание и удаляет его временную копию. Готовый пользовательский файл не удаляется. Ошибка очистки видна, отменённое задание больше не возобновляется; очистку можно повторить.
  • «Отменить ожидающие» обрабатывает снимок queued/paused заданий; активные скачивания продолжаются. «Отменить все» включает активные сетевые передачи. Операции удаления завершённых записей освобождают место в истории очереди.
  • Финальное сохранение начинается только после проверки SHA-256 и закрытия временной записи. В этой фазе пауза/отмена недоступны; закрытие очереди ждёт результат commit. Это не обещание пережить принудительное завершение браузера.
  • Выход, смена токена или пользовательской сессии отменяют старые задания. Каждый job использует зафиксированные credentials в памяти, а не случайно подхватывает новый токен из формы. Смена темы, языка или просматриваемого репозитория не меняет скачиваемый объект.

Параллелизм и задержки ​

Параметр SDKПо умолчаниюДиапазон и смысл
concurrency21–8 заданий, включая retries, запись и commit
maxEntries641–256 записей, включая историю, ошибки и паузы
startIntervalMs2500–60 000 мс между запусками заданий
queueTimeoutMs300 0001–1 800 000 мс ожидания queued задания

В UI настраиваются concurrency, startIntervalMs и queueTimeoutMs (последний в секундах, 1–1800). Снижение concurrency не обрывает активные задания, но задерживает запуск следующих. Paused задания не истекают; явное продолжение задаёт новое окно ожидания. Переполнение очереди отклоняется до начала передачи. Историю нужно очищать; отмена сама по себе сохраняет строку результата.

Это три разных уровня задержек: интервал запуска файлов; ограниченный backoff/Retry-After отдельных HTTP-запросов; серверное ожидание допуска и доступной полосы. Клиентская настройка не может увеличить серверную квоту. Retry policy по-прежнему передаётся в ArkvoryClient; её границы и timeout каждого Range описаны в TRANSFER_RECOVERY.

Временное хранилище браузера ​

BrowserDownloadStorage пишет в приватное OPFS-хранилище origin сегментами по 8 MiB. Закрытый сегмент — checkpoint; reload теряет только ещё не закрытые записи. Сегментация не требует копировать растущий файл при каждом checkpoint. Выбранный пользователем файл назначения открывается для записи только после проверки исходного потока. Частичный файл не сохраняется под видом готового результата. После успешного commit временная копия удаляется; ошибка удаления не превращает успешно сохранённый файл в неудачное скачивание и показывается отдельно.

Снимок prefix полностью хешируется до открытия нового writer: изменение файла может инвалидировать ранее полученный File. На паузе сохраняются только завершённые записи; ошибка записи откатывает текущий writer к предыдущему закрытому checkpoint. При ошибке целостности временная копия удаляется, и следующий явный повтор начинает скачивание заново. В памяти не накапливается целый файл: сетевой блок ограничен 8 MiB, обработка prefix — 1 MiB, конечная копия потоковая.

Нужны Chromium/Edge с File System Access, OPFS и Web Locks и разрешение на выбранный файл. Квота OPFS и свободное место устройства должны вмещать временные данные; commit дополнительно создаёт запись назначения. Серверный лимит размера не гарантирует наличие такой браузерной квоты; при её исчерпании консоль сообщает об ошибке квоты. Токены и конечные file handles не записываются в OPFS/localStorage. В OPFS хранится ограниченный журнал намерений с repository/artifact ID, именем файла и серверной identity. Это приватные локальные данные браузера, не резервная копия.

После reload подключитесь к тому же серверу с той же identity и нажмите «Восстановить очередь». Восстановленные записи находятся на паузе; «Продолжить» заново открывает выбор конечного файла под пользовательским жестом. Новый credentialId получает отдельную область восстановления. Ключ не сохраняется; account/user identity проверяется через API перед чтением журнала. Другой пользователь не получает сохранённые строки. Сервер заново проверяет права при скачивании; префикс хешируется перед Range, полный SHA-256 — до финального сохранения.

В sessionStorage находится только случайный ID рабочей области вкладки. Web Lock исключает одновременное использование staging дублированной вкладкой. Новые вкладки не удаляют незавершённые журналы моложе семи дней даже в промежутке reload; более старые/пустые abandoned области очищаются при следующем открытии workspace, если lock свободен. Закрытие вкладки с потерей sessionStorage, очистка данных сайта, запрет sessionStorage или eviction OPFS не дают гарантии восстановления. Завершённая история и настройки планировщика не сохраняются; восстанавливаются намерения незавершённых скачиваний с последнего закрытого сегмента. Содержимое OPFS ограничено только квотой браузера и свободным местом устройства, очередь — 64 записи.

Отмена/смена identity удаляет журнал загруженных в очередь заданий до удаления staging. Если браузер оборвался в финальном commit, результат назначения может быть уже сохранён: восстановленная запись требует явного выбора назначения и повторной проверки; exactly-once локального сохранения не обещается. Beforeunload предупреждает о работе, но не является механизмом сохранения. ADR 0041.

SDK и адаптеры ​

typescript
import { DownloadQueue, checkpointedDownload } from '@proanima/arkvory-sdk';

const queue = new DownloadQueue({ concurrency: 2, startIntervalMs: 250 });
queue.enqueue(checkpointedDownload(client, jobId, repository, artifactId, storage));
const unsubscribe = queue.subscribe(() => render(queue.snapshot));
queue.pause(jobId);
queue.resume(jobId);
await queue.clearWaiting();
await queue.cancel(jobId);
await queue.clearFinished();
await queue.close();
unsubscribe();

DownloadStorage — узкий клиентский интерфейс: prefix, append, commit, discard. Адаптер должен изолировать staging каждого задания, возвращать стабильный Blob prefix, записывать строго с заданного offset, поддерживать abort writer без порчи предыдущего checkpoint и атомарно публиковать конечный файл. Для Node-приложения нужен файловый адаптер с временным файлом и rename; браузерная реализация находится в web, а SDK не зависит от DOM-элементов или OPFS. Commit/discard не повторяются автоматически. Нельзя подставлять необратимый поток deployment вместо staging.

DownloadQueue управляет состояниями и расписанием, checkpointedDownload — проверяемым переносом в клиентский storage, ArkvoryClient — HTTP/Range/retry, BrowserDownloadStorage — браузерным диском. Сервер продолжает авторизовывать каждый запрос и применять общие/per-principal ограничения. Новых серверных маршрутов и прав доступа не добавлено.

Серверная очередь ​

Дополнены параметры запуска для обоих направлений, с отдельным состоянием upload/download:

EnvironmentDefaultГраница
ARKVORY_TRANSFER_QUEUE_LIMIT641–1024 ожидающих на направление
ARKVORY_TRANSFER_QUEUE_PER_PRINCIPALmin(8, limit)1–limit ожидающих одного клиента
ARKVORY_TRANSFER_QUEUE_TIMEOUT_MS200001–120000 мс

Существующие maxUploads/maxDownloads, per-principal active caps и bytes/s сохраняются. Настройки применяются при запуске; общий HTTP admission в 128 запросов также продолжает действовать, поэтому увеличение waiting limit не создаёт гарантированную дополнительную ёмкость. Readiness показывает waitingCapacity, perPrincipalWaitingCapacity и timeoutMs. HTTP timeout/full queue сохраняют прежние 503/Retry-After. OpenAPI document 0.8.0, inventory по-прежнему 108 операций.

Это очередь клиента и допуски конкретного шлюза. Durable cluster-wide download jobs, динамическое перераспределение полосы, server-side operator cancellation чужих передач и HA остаются отдельными задачами; app/scheduler не объявляется реализованным благодаря клиентской очереди.

Проверки ​

  • Unit: пределы, интервалы, timeout, снижение concurrency, pause/abort/checkpoint, повторный запуск, очистка ожидающих, сбои очистки, запрет отмены commit и обработка ошибок наблюдателя.
  • PostgreSQL + HTTP + диск: pause после 8 MiB, сохранение прежнего destination, Range с точного offset, проверенная публикация и удаление staging, серверный timeout и диагностика очереди.
  • Browser: tests/browser/downloads.mjs, отдельная тестовая БД и установленный Playwright Chromium/Edge. Обходит только нативный диалог выбора: вместо него выдаёт реальные OPFS FileSystemFileHandle. Проверяет HTTP/OPFS/хеш, pause/resume, очистку, RU/EN, светлую/тёмную темы и ширины 390/1440 px. Нативный диалог ОС и квоты на 5 GiB этим тестом не проверяются.

Запуск: npm run gate -- browser с ARKVORY_TEST_DATABASE_URL в .env.test или окружении. Playwright зафиксирован в devDependencies, Chromium устанавливается через npm run test:browser:install; ARKVORY_BROWSER_CHANNEL=msedge явно выбирает установленный Edge. Browser suite требует эксклюзивной тестовой БД, не запускается одновременно с integration suite. Браузерная приёмка обязательна в verify и CI; см. гейты.

Локальный прогон 2026-09-24: Windows, Node.js 24.13.0, PostgreSQL 18.4 — check/сборка, 76 unit tests и 83 integration tests прошли. Browser suite прошёл в headless Edge с 17 MiB, паузой после 8 MiB, проверкой итогового SHA-256 и очисткой abandoned sessions при сохранении живой соседней вкладки. Проверены обе темы/RU/EN/390–1440 px. Это не проверка браузерной квоты 5 GiB и не стендовая приёмка двух серверов.

Arkvory · ProAnimaStudio