Skip to content

Политики хранения, квоты и диагностика ​

Arkvory поддерживает автоочистку зарегистрированных UPack-билдов, настройки последнего N, квоты репозитория и журнал событий. По умолчанию автоочистка выключена, квота репозитория не задана. Глобальный ARKVORY_CAPACITY_BYTES продолжает действовать независимо. Обычные файлы учитываются в квоте, но правила последних N их не удаляют.

Правила последних N ​

grouping выбирает границу счётчика:

ЗначениеСчётчик
package-channelОтдельно по group/name и каждой настроенной метке канала
packageОтдельно по group/name, независимо от меток
repositoryОбщий для всех зарегистрированных билдов репозитория

keepLast — базовый N (1–100000). channels — до 32 пар {label, keepLast} для режима package-channel. Неизвестные метки не создают новые каналы: такие билды входят в общую корзину без канала. Пустой список каналов означает одну корзину на пакет. Названия пакетов сравниваются без учёта регистра; метки — с учётом регистра.

Билд с несколькими каналами или идентичностями сохраняется, если входит в последние N хотя бы одной корзины. Порядок — время публикации, затем UUID, а не SemVer. Защищённые билды участвуют в ранжировании, но никогда не удаляются: поэтому их итоговое количество может превышать N. minAgeHours дополнительно сохраняет свежие билды. По умолчанию защищены bse и release; список можно изменить. Проверяются текущие аннотации, а при их отсутствии — исходные метки загрузки.

Всегда сохраняются внешние references, текущие и исторические asset-ревизии и targets истории вложений. Кандидаты с этими зависимостями отфильтровываются до ограничения порции, поэтому старые закреплённые билды не блокируют продвижение очистки. Версии удалённых пакетов остаются занятыми: повторная публикация с той же идентичностью не заменяет содержимое.

API и SDK ​

Префикс: /api/v1/repositories/{repository}/storage.

Метод и путьПравоРезультат
GET /policystorage.readНастройки, ревизия, расписание и результат последнего запуска
PUT /policystorage.manageПолная замена с expectedRevision; включение дополнительно требует artifact.delete
GET /usagestorage.readОпубликованные, незавершённые и ожидающие GC байты
GET /previewartifact.deleteДо 100 кандидатов сохранённой политики, включая выключенную; hasMore
POST /runstorage.manage + artifact.deleteОдна порция включённой политики с expectedRevision
GET /events?after=…&level=warningdiagnostics.readДо 100 событий по возрастающему sequence; фильтр info, warning, error

GET также поддерживает HEAD. Все права — явные managed key bindings на конкретный репозиторий; legacy read/write и bootstrap не получают их автоматически, а парольные сессии, персональные токены и ключ восстановления не получают вовсе. Console для карточки каталога также требует repository.read и artifact.list. Политика обновляется по CAS: конфликт требует перечитать настройки. Неизвестные свойства запросов отклоняются.

ts
const storage = client.inRepository('builds').storage;
const current = await storage.policy();
const settings = {
  ...current.policy,
  enabled: false,
  grouping: 'package-channel' as const,
  keepLast: 20,
  channels: [
    { label: 'test', keepLast: 10 },
    { label: 'staging', keepLast: 20 },
  ],
  protectedLabels: ['bse', 'release'],
  minAgeHours: 24,
  intervalMinutes: 60,
  quotaBytes: '4398046511104', // пример 4 TiB; не установлен автоматически
  warningPercent: 80,
  criticalPercent: 95,
};
const saved = await storage.configure(current.revision, settings);
const preview = await storage.preview();
// После проверки preview включите политику отдельным осознанным действием:
await storage.configure(saved.revision, { ...settings, enabled: true });

Предпросмотр не резервирует набор: к запуску публикации, метки и ссылки могут измениться. Запуск повторно ранжирует билды и проверяет зависимости под repository catalog gate. В одной короткой транзакции фиксируются максимум 100 tombstones, квитанции и неизменяемый artifact audit. Чтения или удаления blob внутри транзакции нет.

Расписание и авторизация ​

Фоновый цикл работает в writer API, каждые 60 секунд обрабатывает до 20 due-политик последовательно. Reader не запускает очистку. Порция ограничена 100 удалениями; если есть продолжение, следующая назначается через минуту, иначе через intervalMinutes (1–10080). Расписание и результат хранятся в PostgreSQL и переживают перезапуск. Циклы внутри процесса не перекрываются; database gate и повторная проверка due защищают от одновременного выполнения одной scheduled-порции. Ручной /run сознательно позволяет следующую порцию сразу.

Включение связывает расписание с ID текущего управляемого ключа, не с секретом. На каждом запуске заново проверяются срок действия, активность аккаунта и точные storage.manage/artifact.delete; проверка повторяется под блокировкой в транзакции. Отзыв, истечение или сужение прав останавливает удаление и создаёт retention.failed. После ротации сохраните политику новым ключом. Ошибка не запускает бесконечный горячий retry: повтор не ранее следующей минуты. Потеря writer ownership останавливает выдачу новых порций. Это механизм существующего single-writer профиля, не новая HA-гарантия.

Квоты и место ​

Квота — точное десятичное количество байтов (1–9007199254740991), null снимает только лимит репозитория. Учитывается сумма размеров всех ещё не reclaimed загрузок: опубликованные + pending + cancelled. Резервирование сериализуется в PostgreSQL с изменением квоты; параллельные загрузки не обходят лимит. Успешный повтор с прежним idempotency key не резервирует место снова. При превышении нового резервирования сервер возвращает 507 capacity_exceeded.

Уменьшение квоты ниже текущего использования допустимо: существующие резервирования могут завершиться, новые сверх лимита отклоняются. Очистка не удаляет дополнительные защищённые или последние N билды ради квоты. warningPercent и criticalPercent задают предупреждения; переход в новое состояние записывается один раз. Отдельный минутный монитор обрабатывает до 20 наиболее давно проверенных политик, даже если автоудаление выключено или интервал очистки большой. При большом числе репозиториев задержка предупреждения увеличивается на число порций.

reservedBytes — логическое резервирование, не свободное место файловой системы. Staging, части и другие файлы диска могут занимать дополнительное место. Локальный blob-store отдельно проверяет свободное место и сохраняет защитный резерв. Глобальный лимит остаётся общей верхней границей.

Физическая очистка без остановки ​

Логическое удаление запрещает новые скачивания, но сохраняет bytes для уже открытых потоков. retiredBytes остаётся в квоте до фактического GC. Online cleanup работает на writer без остановки API/worker/read gateways: shared pins защищают чтение, занятые uploads откладываются, ёмкость освобождается после удаления. Политика, пауза, порции и результат доступны в API/SDK/консоли. По умолчанию выключена; включать после обновления всех процессов до схемы 17. Прежний npm run gc остаётся отдельным offline repair tool. При выключенной очистке репозитория (по умолчанию) временные parts/ завершённых multipart-загрузок остаются на диске: их удаляет только проход очистки (temp_cleaned) или offline npm run gc.

Диагностика ​

HTTP-ответы 4xx/5xx создают JSON-записи stdout: UTC timestamp, severity, component, machine code, сгенерированный requestId, шаблон маршрута, method и status. Сырые URL/query, ключи, тела запросов и exception messages/stacks не записываются. Worker пишет структурированный результат completion с job ID и кодом, а также ошибки запуска.

Авторизованные managed-запросы к своему репозиторию дополнительно попадают в PostgreSQL через ограниченную очередь: 128 записей, до 10 за секунду. Она не задерживает передачу файлов; переполнение и сбой записи выводят диагностический код в stdout. При backpressure stdout новые записи отбрасываются до drain, затем выводится число пропусков. Это best-effort диагностика, не гарантия доставки всех логов. При закрытии процесса остаётся ограниченный flush; для долговременной доставки используйте внешний сборщик stdout с собственным дисковым буфером.

Журнал PostgreSQL содержит изменения политики, результат очистки, переходы порогов, ошибки расписания и HTTP-ошибки. Хранится максимум 1000 событий репозитория и 20000 глобально. Cursor не является гарантией отсутствия пропусков при pruning; выгружайте события своевременно. Диагностика отделена от audit удалённых артефактов, который при pruning не удаляется. Журнал не содержит email/webhook-оповещений; предупреждения доступны через API и консоль.

UPack: метаданные внутри архива ​

Формат UPack разрешает дополнительные поля корневого upack.json, рекомендуя префикс _. Они могут содержать вложенные JSON-объекты и массивы. Файлы за пределами package/ относятся к metacontent — например, дополнительные манифесты или SBOM. Arkvory сохраняет исходные custom-поля при регистрации UPack; сам архив доступен без модификации.

Подготовка манифеста:

sh
npm run build
npm run upack:manifest -- --input manifest.json --metadata custom.json --output upack.json

Пример custom.json:

json
{
  "_build": { "number": 1842, "commit": "abc123", "targets": ["windows", "linux"] },
  "_labels": ["test", "staging"]
}

Команда сливает поля первого уровня; совпадающее custom-поле заменяется целиком. Имена добавляемых полей должны начинаться с _, стандартные name/version нельзя подменить через custom.json. Проверяются идентичность и лимит 64 KiB; существующий выходной файл не перезаписывается. Включите результат как корневой upack.json при создании нового архива обычным UPack packager. Команда не переупаковывает готовый архив. ZIP64/большие файлы обрабатываются существующим потоковым upload.

_labels внутри UPack — произвольное custom-поле, оно не синхронизируется автоматически с индексируемыми Arkvory annotations/labels. Для политики хранения задавайте эти метки в descriptor или annotations API. Метаданные Arkvory и связанные вложения можно менять без перезаписи UPack. Изменение внутренних полей уже опубликованного UPack меняет его bytes и SHA-256: нужна новая версия/артефакт, а не правка blob на месте.

Обновление ​

Миграция 15 добавляет таблицы политик и диагностик. Выполните migrate, затем обновите writer, worker и readers. До обновления всех процессов не выдавайте ключам новые actions: старые парсеры их не знают. Единственный writer должен быть обновлён до включения квот, иначе старый код не проверяет их. Новые политики не активируются самой миграцией.

Arkvory · ProAnimaStudio