Постоянство данных и обмен рабочими процессами в 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
- Создайте артефакт с новым файлом и загрузите его, связанный с запуском рабочего процесса. Для этого вы можете использовать action/upload-artifact@v3.
- 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}”
Если вы зашли так далеко, спасибо! Я надеюсь, что это было полезно.