Как, загружая гемы Ruby из кеша в GitHub Actions, ускорить запуск сборки проекта в этой системе непрерывной интеграции (CI)? Если суметь подготовить к работе все зависимости Ruby on Rails (RoR)-проекта в кратчайшие сроки, это позволит сократить время, необходимое на запуск тестов для такого проекта. Тут-то нам и пригодится кеширование. Гемы Ruby, нужные в проекте, можно кешировать средствами GitHub Actions, благодаря чему их, при запуске CI-конвейера, можно будет загрузить гораздо быстрее, чем прежде. Существует два способа кеширования гемов Ruby, применимых при использовании CI GitHub Actions. Один из них предусматривает применение ruby/setup-ruby, а второй — actions/cache.

  • actions/cache — это популярное решение для кеширования гемов Ruby.
  • ruby/setup-ruby — это решение, направленное на установку конкретной версии Ruby и на кеширование гемов Ruby с помощью бандлера. Фактически, речь идёт о двух возможностях одного «экшена» (того, что в терминологии GitHub Actions называется «action»).



Actions/cache — кеширование зависимостей и больше ничего


Actions/cache — это популярное решение, которое может быть использовано для размещения данных в кеше и для их извлечения из кеша при очередном запуске процесса сборки проекта в CI-системе. Часто этот экшен используют для RoR-проектов, в которых, кроме того, для управления версиями Ruby в GitHub Actions, используется экшн actions/setup-ruby.

Рассмотрим пример конфигурационного файла для организации кеширования в GitHub Actions, в котором используется actions/cache:

# .github/workflows/main.yml
name: Main
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - uses: actions/cache@v2
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Bundle install
        env:
          RAILS_ENV: test
        run: |
          bundle config path vendor/bundle
          bundle install --jobs 4 --retry 3

Разберём основные особенности этого файла:

  • Нужно указать путь к директории, которую требуется кешировать. В нашем случае это — vendor/bundle.
  • Кроме того, тут мы генерируем уникальный ключ (key) кеша, применяя при этом сведения о версии операционной системы и о файле Gemfile.lock. Изменение версии операционной системы или установка нового гема, из-за чего изменяется Gemfile.lock, приводит к генерированию нового значения key.
  • Далее, надо настроить бандлер так, чтобы он устанавливал бы все наши гемы Ruby в директорию vendor/bundle.
  • Тут можно использовать следующие параметры бандлера:

Если вам интересно взглянуть на полные YAML-файлы с настройками GitHub Actions для Rail-проектов — вот, вот, вот и вот — несколько наших статей на эту тему.

Ruby/setup-ruby — установка Ruby и кеширование гемов


Выше мы упоминали о том, что в RoR-проектах часто используется actions/setup-ruby. Но экшен actions/setup-ruby был объявлен устаревшим. Вместо него в наши дни рекомендуется пользоваться экшеном ruby/setup-ruby. В нём, помимо прочих возможностей, имеется и возможность кеширования данных. Вот как выглядит конфигурационный файл, рассчитанный на использование ruby/setup-ruby:

# .github/workflows/main.yml
name: Main
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - uses: ruby/setup-ruby@v1
      with:
        # Не нужно при наличии файла.ruby-version
        ruby-version: 2.7
        # запускает 'bundle install' и автоматически кеширует установленные гемы
        bundler-cache: true

    # запуск RSpec-тестов
    - run: bundle exec rspec

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

А вот что можно узнать, обратившись к документации по ruby/setup-ruby:

Можно, кроме того, кешировать гемы вручную, но поступать так не рекомендуется. При таком подходе, во-первых, увеличиваются объёмы конфигурационных файлов, а во-вторых — вручную очень сложно настроить кеширование правильно. В расчёт нужно принять много всего, а это значит, что actions/cache никогда не бывает достаточно для кеширования гемов (например — речь идёт о неполных ключах кеша, об удалении старых гемов при восстановлении данных с использованием ключа, отличающегося от текущего, о корректном хешировании .lock-файлов, сведения об изменениях которых не внесены в систему контроля версий, об учёте версии ОС, о принятии во внимание вопросов ABI-совместимости для ruby-head и так далее). Поэтому, пожалуйста, вместо ручной настройки кеширования, пользуйтесь опцией bundler-cache: true…

Итоги


Мы рассмотрели два способа кеширования гемов Ruby в CI GitHub Actions. Надеемся, что тот, кто нуждается в ускорении сборки Ruby-проектов, нашёл здесь пищу для размышлений. Но, конечно, есть и другие способы ускорения CI-конвейеров, например — параллельное выполнение тестов.

Пользуетесь ли вы GitHub Actions?