Постоянство данных и обмен рабочими процессами в GitHub

Я уже некоторое время работаю с GitHub, и пайплайны не всегда ведут себя так, как мы того хотим. У вас когда-нибудь был один из тех дней, когда все функции и пользовательские истории должны быть закрыты и объединены в вашей основной ветке? Вы, скорее всего, пережили эту апокалиптическую сцену, когда все спешат закончить свою работу, а лавина запросов на вытягивание запускает проверки и развертывания.

Тем не менее, это вас не беспокоит, ведь ваши процессы CI/CD автоматизированы и все работает как надо.

В идеальном мире так и должно быть, но в реальности количество исправлений, проверок и действий в GitHub может в конечном итоге создать узкое место. Это уже случалось со мной раньше, и единственным способом разблокировать конвейер, который у меня был в то время, был поиск процессов, душивших поток и убивавших устаревшие и дублированные.

Проще говоря, параллелизм — это повторяющаяся тема, которая возникает при работе в CI/CD. Если вы работаете над Agile-проектами или в спринтах, эта сцена, скорее всего, будет повторяться каждые две недели. Но можем ли мы вырваться из ситуации, похожей на День сурка? Немного покопавшись, я пришел к выводу, что действительно можно, есть надежда на пайплайн!

Можем ли мы освободиться от этого Дня сурка?

Я начал с определения происхождения параллелизма из предыдущего опыта, который у меня был. Мне удалось определить два возможных триггера параллелизма:

  • Несколько рабочих процессов запускаются для одного запроса на включение за короткий промежуток времени в GitHub.
  • Задания во внешних системах запускаются действием, и их нельзя отменить, кроме как вручную.

Зная причины, я начал борьбу с параллелизмом в GitHub и во внешних заданиях, запускаемых действиями.

Как избежать параллелизма в GitHub

Эта первая проблема решается на удивление легко! Вы можете настроить действия GitHub для проверки параллелизма перед запуском любого рабочего процесса. Использование этой конфигурации остановит любой запущенный рабочий процесс и отдаст приоритет последнему.

Посмотрите пример ниже, чтобы узнать, как это будет выглядеть.

Как избежать параллелизма во внешних системах с помощью GitHub

Этот тип параллелизма немного сложнее остановить, потому что остановка действий в GitHub не останавливает их в других системах, и нет стандартного способа связи между запусками рабочего процесса. Кроме того, при запуске задания в другой системе вы, скорее всего, получите только идентификатор задания из этой системы, который сообщает нам, что выполнение началось. Затем идентификатор будет сохранен либо в кеше, либо во временной переменной, которая исчезнет после завершения рабочего процесса, но ваша внешняя система продолжит работу в фоновом режиме.

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

Они сохраняются между запусками рабочего процесса, и с последней версией GitHub API мы можем получить к ним доступ из наших действий. Это именно то, что я сделал, чтобы сообщить о рабочих процессах и запусках. Основная идея потока заключается в следующем.

  • Для текущего задания создайте файл со ссылкой на идентификатор задания, который возвращает внешняя система. Вот пример того, как это сделать,
#replace here the github.run_id by you system's id
- name: Create file with id      
      run: |
         echo "Writing in workflow log file..." 
         echo ${{ github.run_id }} >> WorkflowRunLog.txt
- name: Upload Workflow Artifact
      uses: actions/upload-artifact@v3
      with:          
        name: ${{ github.head_ref }} # source branch of the PR
        path: WorkflowRunLog.txt
  • Убедитесь, что параллельное задание выполняется в GitHub, и остановите его, используя первую конфигурацию статьи. Продолжите извлечение последнего артефакта для ветки, в которой вы работаете, и получите идентификатор.
- name: Get artifact for specific branch
  id: get-artifact
  run: |          
   input_file="WorkflowRunLog.txt"
   artifactFile=$(gh run download -n "concurrency-job-level")
   jobId=$( tail -n 1  ${input_file} )
   echo "${jobId}"
   echo ::set-output name=job_id::$(tail -n 1 ${input_file})

В примере я загружаю артефакт напрямую по имени, но вы можете поиграться со своими спецификациями. Не забудьте установить GitHub API CLI, если у вас его еще нет.

#retrieve a specific artifact in a branch
gh api -H “Accept: application/vnd.github+json” /repos/<username>/<repo name>/actions/artifacts — jq “.artifacts[] | select(.workflow_run.head_branch == \”concurrency-job-level\”)”

Вы увидите, что ответ возвращает URL-адрес, откуда мы можем загрузить фактический артефакт и получить доступ к содержащейся в нем информации. Используйте приведенную ниже команду, чтобы получить только фактический URL-адрес, вы можете просмотреть информацию, используя bash или другие языки сценариев.

#retrieve a specific artifact
gh api -H “Accept: application/vnd.github+json” /repos/<username>/<repo name>/actions/artifacts — jq “.artifacts[] | select(.workflow_run.head_branch == \”concurrency-job-level\”) | {archive_download_url}”

Если вы зашли так далеко, спасибо! Я надеюсь, что это было полезно.