기록/Git Action

남은 PR 디스코드 비동기 알림 CI 만들기 (CI로 코드리뷰 문화 활성화-1)

코딩신생아(0o0) 2025. 2. 9. 05:05
상황

 

개발은 잘 진행되고 있는 것 같은데, PR(pull request)는 계속 쌓이고, 점차 레거시 코드를 갖고 있기 때문에 이를 새로운 것으로 다시 병합하고 수정하는 시간들이 길어져 프로젝트에 들이는 시간대비 효율성이 나오는 것 같지 않다는 생각이 들었다.

추가로 개인적으로 코드 리뷰를 하는 것, 받는 것 자체가 재밌고, 개발의 원동력을 준다고 생각하는데, 이런 부분이 PR을 올린 시점으로부터 늦어지면 팀원 모두의 참여도에 영향을 미칠 것 같았다.

원인 분석

 

PR이 쌓이는 주된 원인이 무엇일까? develop 브랜치에 머지하기 전에 코드리뷰 및 승인을 받아야 하는데, 이 부분에서 너무 지체된다고 생각했다. 

해결방안 모색

 

따라서 아직 머지 안된 PR들의 목록과 함께 매일 특정 시간에 알려주는 시스템이 있으면 남은 PR이 있다는 것을 팀원 모두가 인지하는데 도움을 줄 수 있다고 생각했고, 코드승인까지 지체되는 시간을 줄여 개발 생산성을 조금이라도 높일 수 있을 것 같다고 생각했다. 이를 적용할 수 있는 깃 액션 워크플로우를 만들었다.


리뷰 알람

 

깃허브 레포의 setting에서 webhook 설정이 가능해  PR이 올라왔을때나 다른 이벤트가 발생했을 때의 트리거를 통해 외부로 정보를 보낼 수 있다.

github marketplace 에서는 slack 에 대한 알림만 가능해서 우리 팀은 디스코드를 활성화 할 것이기 때문에 디스코드로 알림이 가도록 구현해보았다.

구현한 PR 알림

 

pr-remaining.yml 

 

깃 액션을 시작할 수 있게끔 아래와 같이 yml 파일을 작성하였다. 

name: Remaining PR
on:
  schedule:
  - cron: '0 7 * * *'  # 매일 16:00 KTC (한국 시간 = UTC+9)
permissions:
  contents: read
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
      ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python 3.9
        uses: actions/setup-python@v3
        with:
          python-version: "3.9"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

      - name: run remainingPR.py
        run: |
          python remainingPR.py

Cron 스케줄링을 사용할 수 있는 옵션이 있어 사용해봤다. 그런데, 실제로는 해당 16:00시각에 알림이 가는게 아니라, 16:08, 16:10 등 10분 정도 늦춰져 알림이 가는 현상이 발생했다.

깃허브 공식 문서 Schedule

이에 대해 알아보니, 엄청난 유저 수의 cron을 처리하다보니 큐에 쌓여 딜레이가 생겨서 이런 현상이 일어난다고 한다.

10분 정도는 작은 차이일 수 있지만, 이런 깃액션 cron 오차에 대해 알아보니, 어떤 케이스에서는 2시간 뒤에 작업이 실행된다는 글을 봐서 충분히 문제가 될 수 있겠다 생각하였다. 이부분에 대해서는 아래에 내용을 썼다.

 

remainingPR.py

 

pr-remaining.yml 에 사용된 remainingPR.py 은 다음과 같은 플로우로 진행된다.

# 디스코드 채널로 메세지 전송
def discord_send_message(text):
    value = set_pull_requests_tags()
    print(value)
    now = datetime.datetime.now()
    now_kst = now + datetime.timedelta(hours=9)  # KST 변환

    message = {
        "content": "",  # 메인 메시지는 비워두고
        "embeds": [{
            "title": "Merge 안된 PR 목록",
            "description": str(text),
            "color": 5814783,  # 푸른색 계열
            "footer": {
                "text": f"알림 시각: {now_kst.strftime('%Y-%m-%d %H:%M:%S')} (KST)"
            },
            "fields": [
                {
                    "name": "",
                    "value": value,
                    "inline": True
                }
            ]
        }]
    }

    response = requests.post(
        DISCORD_URL,
        json=message  # data 대신 json을 사용하면 자동으로 JSON 직렬화됨
    )

디스코드 채널로 메시지를 전송하는 부분의 로직은 위와 같다. 코드를 짜고 보니, 추후에 남은 PR이 없을 때, D-라벨이 없는 경우 예외처리를 해야될 것 같다.  

 

Cron 제시간 실행되지 않는 문제

 

사실 이부분에 대해서 깊게 고민해야 될 필요성을 느낀 이유가 3가지가 있다. 

1) 추후 2시간 정도의 지연 가능성을 방지하기 위해서
2) 확장 기능으로 특정 시간 간격으로 comment 알림, 서버 헬스 체크 등 다른 부분들을 추가해서 구현하려 했는데, 특정 시간이 늦춰지면 치명적인 알림 기능인 경우 지연되면 안됨
3) cron이 딜레이 되는 최대 시간대를 알 수 없음 ( 운이 나쁘면 2시간 딜레이 가능성 있음

따라서 반드시 정확한 시간에 실행이 되도록 해야된다.  git action에서 제공하는 cron을 제 시각에 실행시킬 방법은 없는 것 같아 third party 를 도입하려 한다.

third party scheduling service

 

지금 생각한 것은 aws 에 서버리스 lambda를 사용하는 것.

일단 기존에 위 비동기 알림 기능을 위해 만들어두었던 테스트를 사용해서 구현 시도를 해보려 한다.

 

왜 cron을 큐로 처리 할까?

 

먼저 cron을 설정한 사람들은 당연히 먼저 실행되어야 할 것이고, 유저수가 엄청나서 2시간 가량 딜레이 되는 상황이다. 큐가 가장 적합하다고 해서 깃허브에서 큐를 사용했으나, third party를 사용하지 않고 깃허브의 큐 로직을 바꾼다면 다른 방법은 없을까?

 

참고

[코드리뷰의 활성화]

[github action cron이 제시간에 실행되지 않는 문제]

[Third-party scheduling service]