Перейти к содержанию

Кэш и воспроизводимый результат

Курс «Лаборатория GitLab CI/CD»

Граф лаборатории course-card уже разделяет сборку сайта и анализ исходного каталога. Добавим кэш к анализу, чтобы изучить повторное использование промежуточного результата. Это небольшой учебный пример: для трёх записей кэш не даёт практически значимого ускорения. Его задача — показать договор, при котором отсутствие или устаревание сохранённых данных не меняет правильный результат.

Сборку dist/ по-прежнему передаём только через artifacts. Кэш не станет запасным источником выпуска. Если он отсутствует, анализатор должен пересчитать сводку из JSON; если артефакт build отсутствует, verify должен завершиться понятной ошибкой. Такое различие защищает смысл проверки.

Ключ связан с входом

В job analyze-catalog добавьте следующий блок. Команда node scripts/analyze.mjs уже существует; программа самостоятельно умеет работать без сохранённой сводки. Папка .cache/ не входит в результат сайта.

cache:
  key:
    prefix: course-summary-v1
    files:
      - courses.json
  paths:
    - .cache/
  policy: pull-push

key:files связывает ключ с содержимым указанного файла. Префикс отражает версию алгоритма сводки. Если мы изменим смысл вычисления, но сохраним прежний JSON, следует изменить префикс или иной вход ключа. Один хэш данных не учитывает автоматически каждую редакцию программы, поэтому договор должен включать и алгоритм.

paths указывает папку, которую сохраняем и восстанавливаем. pull-push разрешает получать существующий кэш и обновлять его после работы. При политике pull job только читает сохранённый результат, при push — только записывает. Эти режимы полезны при нескольких потребителях, чтобы не создавать ненужные конкурирующие записи. Подробности изложены в документации кэширования GitLab.

Программа не доверяет имени

Анализатор вычисляет fingerprint исходного JSON и сравнивает его со значением в .cache/summary.json. Если файл отсутствует, повреждён или содержит другой fingerprint, программа заново считает количество курсов и суммарное число уроков. Она не предполагает правильность содержимого только потому, что Runner восстановил папку с ожидаемым ключом.

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

Для наших трёх записей ожидаем три курса и двадцать четыре урока: восемь, десять и шесть. Эта сумма получена из учебных данных, а не из запущенного измерения. В отчёте анализа должны быть одинаковые значения при cache hit и cache miss. Различаться может диагностическая подпись источника сводки, но не число уроков.

Повреждённый кэш — повод для пересчёта, а не для успешного использования произвольного старого числа. Если при ошибке чтения программа возвращает ноль, она уже меняет содержание результата. Обработка должна различать необязательный промежуточный файл и обязательный исходный JSON. Ошибка в JSON по-прежнему существенна и завершает job неуспешно.

catalog: 3 courses, 24 lessons
summary source: calculated or cache

Это форма ожидаемого сообщения. Конкретную подпись calculated либо cache программа выбирает после чтения файлов. Вывод не является показателем производительности. Нельзя объявить ускорение в два раза по наличию слова cache: оно сообщает только, какую ветвь алгоритма использовали.

Доступность и область

Кэш может отсутствовать после смены runner, очистки или из-за особенностей настроенного хранилища. Возможность делиться им между исполнителями зависит от инфраструктуры. Поэтому job не должен требовать кэш как обязательный вход. Наш алгоритм всегда сохраняет путь полного пересчёта и получает правильный результат без предварительного запуска.

По умолчанию GitLab может разделять кэши защищённых и незащищённых веток. Это важно для границы доверия: данные из внешней ветки не должны автоматически становиться надёжным источником рабочего выпуска. Не отключайте такое разделение только ради увеличения числа попаданий. В нашей лаборатории cache не участвует в разрешении staging и не содержит секретов.

Не сохраняйте reports/ вместе с .cache/. Отчёт относится к конкретной работе, а промежуточная сводка может использоваться повторно. Если старый verify report попадёт в новый job, интерфейс получит сведения о другой версии. Каждая папка должна сохраняться механизмом, соответствующим назначению её данных.

Данные Механизм Почему
dist Artifacts Результат конкретной сборки
reports Artifacts Диагностика конкретного job
.cache/summary.json Cache Необязательное повторное вычисление
Секреты доступа Переменные или специальное хранилище Не должны распространяться с файловым результатом

Когда кэш лишний

Для нашей маленькой сводки расходы восстановления и сохранения могут быть больше самого вычисления. В настоящем проекте сначала измеряют дорогие шаги, затем добавляют кэш с понятными входами. Наличие слова cache в YAML не является признаком зрелого pipeline. Иногда отсутствие кэша делает процесс проще и достаточно быстрым.

В проектах с внешними зависимостями часто кэшируют каталоги загрузок менеджера пакетов. Это отличается от копирования всей установленной среды между разными версиями образа. Наш курс не вводит npm-зависимости и не требует установки, поэтому такой вариант оставляем за пределами практического примера. Механизм ключа при этом остаётся тем же: учитываем входы и совместимость результата.

Измените один учебный курс, добавив ещё одно занятие. Ожидаем, что fingerprint изменится, сводка пересчитается и сумма станет двадцать пять. Если программа продолжает показывать двадцать четыре, кэш используется без проверки входа. Такой случай даёт содержательный критерий корректности, не зависящий от скорости компьютера.

Если алгоритм сводки меняется, одной редакции программы недостаточно для объяснения старого кэша. В нашем файле есть algorithm: 1, а в конфигурации prefix: course-summary-v1. При переходе к другой структуре обновите обе стороны договора. Программа должна отвергнуть неподдерживаемую схему и пересчитать результат. Это полезнее, чем пытаться вручную исправлять каждую сохранённую копию. При этом новая версия исходного JSON по-прежнему влияет на fingerprint. Так в одном небольшом примере различаются совместимость структуры и идентичность данных, которые часто ошибочно смешивают в одно имя ключа.

Выход текущего шага

После урока анализатор имеет два пути — вычисление и повторное использование — с одинаковым предметным результатом. Build и verify не читают его кэш и продолжают работать с артефактом своего pipeline. Состояние кэша может объяснить часть журнала, но не заменяет происхождение выпуска.

В полном файле архива алгоритм сводки проверяет fingerprint и не запускает внешние команды. При подготовке курса ни его ветви, ни политика Runner не выполнялись. На следующем шаге добавим переменные конфигурации и отдельно разберём значения, которые передаются между заданиями после сборки.