craftrun

굴리기

매일 아침 알림이 점심에 왔다

무료 CI의 예약 실행은 정시에 안 옵니다. 3~5시간씩 밀렸고, 시간을 바꿔도 소용없었습니다. 30초 오차로 되돌린 방법.

매일 아침 9시에 전날 현황을 요약해 보내는 알림을 만들었습니다. 방문자, 유입 경로, 수익, 검색 노출을 한 장으로 보는 것입니다.

만들고 며칠 지나서 이상한 걸 눈치챘습니다. 알림이 아침에 안 왔습니다. 어떤 날은 오후에, 어떤 날은 점심때 왔습니다.

예약 실행은 정시가 아니다

기록을 모아 보니 이랬습니다.

예정실제 실행
00:17 (UTC)03:53
00:1705:42

3~5시간씩 밀렸습니다.

처음에는 제 설정이 틀린 줄 알고 크론 표현식을 몇 번이나 다시 봤습니다. 맞았습니다. 시간을 바꿔 보기도 했습니다 — 정각을 피해 17분처럼 어중간한 시각으로 옮기면 낫다는 이야기가 있어서요. 차이가 없었습니다.

원인은 제 쪽이 아니었습니다. 무료 CI의 예약 실행은 여유 자원이 생길 때 처리되는 구조입니다. 전 세계 사용자의 예약이 같은 시각에 몰리면 순서를 기다립니다. 문서에도 지연될 수 있다고 적혀 있고, 실제로는 "가끔"이 아니라 매일 밀렸습니다.

이건 고칠 수 없는 종류의 문제입니다. 제 코드가 아니니까요.

시도 1: 내 컴퓨터에서 쏘기

그래서 방향을 바꿨습니다. 정시에 신호를 보내는 역할만 따로 떼어내면 되겠다 싶었습니다. 신호를 받으면 CI가 바로 실행하니까요.

처음엔 제 노트북에 예약을 걸었습니다. 정해진 시각에 명령을 실행하는 기능은 운영체제에 이미 있습니다.

며칠 만에 실패했습니다. 이유가 여러 겹이었습니다.

교훈: 개인 컴퓨터는 정시 실행의 주체가 될 수 없습니다. 켜져 있다는 보장이 없고, 켜져 있어도 깨어 있다는 보장이 없습니다.

시도 2: 항상 깨어 있는 곳에서 쏘기

다음으로 옮긴 곳은 엣지 함수였습니다. 짧은 코드를 올려 두면 정해진 시각에 실행해 주는 서비스인데, 무료 한도가 있고 그 한도가 꽤 넉넉합니다.

하는 일은 정말 단순합니다.

  1. 정해진 시각에 깨어난다
  2. CI에 "이 워크플로 지금 실행해" 요청을 보낸다

실행 자체는 여전히 CI가 합니다. 정시에 두드리는 역할만 옮긴 것입니다.

결과를 재봤습니다.

예정 01:10:00 → 실제 발사 01:10:30

오차 30초. 3~5시간이 30초가 됐습니다.

원래 예약은 지우지 않았다

여기서 한 가지 결정을 했습니다. CI 쪽의 원래 예약 설정을 지우지 않고 그대로 뒀습니다.

엣지 함수가 죽으면 알림이 아예 안 옵니다. 그런데 원래 예약이 살아 있으면, 늦게나마 실행은 됩니다. 정확한 경로 하나 + 느린 경로 하나를 겹쳐 둔 셈입니다.

대신 이러면 하루에 두 번 실행될 수 있습니다. 그래서 워크플로 안에 "오늘 이미 성공했으면 건너뛴다"는 확인을 넣었습니다. 먼저 도착한 쪽이 일하고, 늦게 온 쪽은 조용히 물러납니다.

안 도는 건 아무도 모른다

이 일을 겪으면서 하나 더 깨달았습니다.

워크플로가 실패하면 알림이 옵니다. 그런데 아예 실행되지 않으면 아무 일도 일어나지 않습니다.

실패는 눈에 띕니다. 빨간 표시가 뜨고 메일이 옵니다. 하지만 "오늘 안 돌았음"은 침묵입니다. 실제로 한 번은 실행기가 멈춰서 하루치 데이터 수집이 통째로 빠졌는데, 며칠 뒤에야 알았습니다.

그래서 "안 돈 것"을 잡는 감시를 따로 만들었습니다. 각 예약 작업마다 "이 주기 안에 한 번은 성공해야 한다"는 기준을 정해 두고, 그걸 넘기면 알립니다.

청약 데이터 수집  — 8일 안에 한 번
주가 갱신        — 80시간 안에 한 번 (주말 공백 포함)
일일 알림        — 28시간 안에 한 번

기준을 넉넉하게 잡은 이유가 있습니다. 빡빡하게 잡으면 정상적인 흔들림에도 알림이 오고, 그러면 며칠 만에 알림을 안 보게 됩니다. 감시는 진짜일 때만 울려야 합니다.

정리

크론GitHub ActionsCloudflare Workers자동화