목표: 매주 월요일에 워크플로우가 오늘의 참조 도메인과 앵커 텍스트를 저장소에 기록합니다. 그 외의 작업은 없습니다. 비교 분석은 나중에 진행합니다.
Linkzoid 편집팀 ·
시작하기 전에
저장소, 시크릿 LZ_KEY로 저장된 Linkzoid 키, 그리고 귀하가 소유한 도메인 하나가 필요합니다. 예산: 실행당 대상당 약 6 크레딧, 즉 $0.0006입니다. 스냅샷은 한 달간의 사실을 나타내므로 주간 실행은 대부분 동일한 인덱스를 다시 가져옵니다. 이렇게 내 웹사이트의 백링크를 확인하는 방법을 설정하는 데 한 저녁이 소요됩니다.
순서대로 실행하는 러너북
01
1. 시크릿 추가
저장소 설정, 그다음 '시크릿 및 변수', 그다음 '액션'으로 이동합니다. 이름은 LZ_KEY로 지정합니다. 워크플로우 파일에 붙여넣는 경우, 오늘 키를 회전(갱신)하세요.
02
2. 스크립트 커밋
아래 Python 코드를 snap.py로 저장합니다. 이 스크립트는 data/YYYY-MM-DD/refdomains.json을 작성하며, ok가 false인 응답이 있을 경우 실패합니다.
03
3. 워크플로우 커밋
아래 YAML을 사용합니다. workflow_dispatch 트리거를 사용하여 한 번 수동으로 실행하고, 스케줄을 신뢰하기 전에 로그를 확인하세요.
04
4. 첫 번째 파일 확인
JSON 파일을 엽니다. total과 행 수를 대조하고, 무료 overview 호출에서 도메인에 대해 보고한 숫자와 비교하세요.
05
5. 알림 추가
실패한 작업은 기본적으로 저장소 소유자에게 이메일을 보냅니다. 이를 유지하세요. 조용히 중단되는 작업은 이러한 설정이 실패하는 일반적인 방식입니다.
snap.py
표준 라이브러리입니다. 루프는 추측이 아닌 개수 기준으로 종료됩니다.
python
import json, os, sys, datetime, pathlib, urllib.request as u
KEY = os.environ['LZ_KEY']
TARGET = sys.argv[1]
def get(**p):
q = '&'.join(f'{k}={v}' for k, v in p.items())
url = f'https://linkzoid.pro/api.php?{q}&key={KEY}'
with u.urlopen(url, timeout=30) as r:
return json.load(r)
rows, page = [], 1
while True:
d = get(action='refdomains', q=TARGET, page=page, per=1000)
if not d['ok']:
sys.exit(f'bad response: {d}')
rows += d['rows']
if not d['rows'] or len(rows) >= d['total']:
break
page += 1
day = datetime.date.today().isoformat()
out = pathlib.Path('data') / day
out.mkdir(parents=True, exist_ok=True)
(out / 'refdomains.json').write_text(json.dumps(rows))
print(len(rows), 'rows, balance', d['_credits'])
.github/workflows/snapshot.yml
GitHub의 Cron은 UTC에서 실행되며 러너가 바쁠 경우 시작이 늦어질 수 있습니다. 분 단위에 의존하는 작업을 구축하지 마세요.
워크플로우 파일은 기본 브랜치에 위치합니다. 스케줄러가 읽는 복사본이 바로 그곳에 있기 때문입니다.
workflow_dispatch를 사용한 수동 실행이 완료되었으며, 날짜가 포함된 폴더가 하나 생성되었습니다.
파일의 행 수는 해당 API 호출에서 반환된 총 행 수와 일치합니다.
잘못된 응답 시 작업이 비-zero 상태로 종료되므로, 실패 시 실행 상태가 빨간색으로 표시됩니다.
발생하는 오류 및 해결 방법
스케줄링된 백링크 작업에서 가장 먼저 문제가 되는 부분
오류
발생 현상
해결 방법
YAML에 키를 직접 붙여넣음
키가 리포지토리 이력(history)에 노출됨
secrets.LZ_KEY로 이동하여 회전하세요
0 0 같은 이상한 분
실행이 20분 늦게 시작됨
17 6을 선택하세요; 정각은 혼잡합니다
레포지토리 60일 동안 대기 상태
GitHub이 일정을 일시 중지함
커밋하거나 Actions 탭에서 다시 활성화하세요
빈 페이지에서만 루프가 중지됨
페이지 한도에 도달하면 무한 실행
len(rows) >= total일 때도 중지
종료 코드 무시됨
초록색 체크, 빈 폴더
ok: false일 때 sys.exit 사용
변경 사항이 없을 때 커밋 실패
무의미한 실행으로 인한 빨간색 표시
커밋 뒤에 || exit 0 추가
키와 저장소 안전하게 유지하기
이 설정에서 보호할 대상은 키가 유일합니다. 지갑의 잔액을 사용할 수 있는 사람이 키를 소유하고 있으므로, 키를 비밀번호처럼 취급하세요.
스케줄된 작업은 조용히 누수됩니다. 로그에 붙여넣은 키, 공개 저장소로 복사된 워크플로우, 또는 쓰기 권한이 있는 전직 동료 등이 일반적인 유출 경로입니다. 분기별로 한 번씩 각 항목을 확인하세요.
직원이 퇴사할 때 키 교체
접근 권한이 있는 동료가 퇴사하면 새 키를 생성하고 시크릿을 업데이트한 후 이전 키를 폐기하세요. 그런 다음 다음 실행이 성공했는지 확인하세요. 변경 후 한 번의 녹색 실행은 일년 동안 할 수 있는 가장 저렴한 테스트입니다. 다음 교체가 놀라움이 없도록 저장소 노트에 교체 날짜도 기록하세요.
워크플로우 편집 권한 제한
YAML을 편집할 수 있는 사람은 누구나 실행 중 시크릿을 출력할 수 있습니다. 쓰기 권한을 짧게 유지하고, 워크플로우 파일의 변경 사항을 코드 검토하듯이 검토하세요. 작은 저장소의 경우 쓰기 권한이 있는 사람이 두 명이면 보통 충분합니다.
요청 URL 출력하지 않기
잔액과 행 수를 출력하되, 요청 URL은 출력하지 마세요. 키는 쿼리 문자열을 통해 전달되므로 URL을 출력하는 디버그 줄은 키를 로그에 기록하게 됩니다. 이슈에서 요청을 공유해야 하는 경우, 먼저 키를 자리 표시자로 바꾸세요.
스냅샷이란 무엇이며, 무엇인가
제공되는 것은 월간 스냅샷입니다. 자체 크롤러가 인덱스를 월 약 한 번씩 갱신하므로, 같은 달의 두 월요일 실행은 종종 동일한 행을 반환합니다. 이는 정상적인 현상입니다.
주간 주기가 적합합니다. 습관을 유지할 수 있으며, 실패한 작업을 30일이 아닌 7일 이내에 발견할 수 있습니다. 화요일에 구축한 링크가 월요일에 누락된 경우, 당황하기 전에 다음 갱신까지 기다리세요.
날짜가 있는 폴더가 3~4개 쌓이면 SQLite 차분으로 넘어가세요. 고집스러운 응답 코드에 막혔다면 속도 제한 테이블이 루프에서 각 상태가 의미하는 바를 나열합니다.
첫 번째 폴더를 기준선으로 유지하세요. 이후의 모든 비교는 이를 참조하며, 날짜로 이름이 지어진 폴더는 작년 봄의 숫자가 어땠는지 기억하는 것보다 훨씬 신뢰하기 쉽습니다. 일관성을 유지하세요.
앵커 및 상위 페이지 추가
파일당 하나의 작업으로 차분(diffs)을 가독성 있게 유지하세요. snap.py의 루프를 복사하고 refdomains를 anchors 또는 toppages로 변경한 후 두 번째 파일명으로 저장하세요. 각 작업에는 2크레딧이 필요합니다.
복합 파일은 어느 부분이 변경되었는지 숨기며, 풀 리퀘스트를 스크롤하는 검토자는 차분당 하나의 개념만 보고 싶어 합니다. 분리하세요. 세 도메인을 추적하는 경우 워크플로우에서 짧은 목록에 대해 루프를 도는 행렬(matrix)을 사용하여 각 대상에 고유한 작업과 고유한 실패를 부여하세요.
앵커는 고유한 차분 캡(caps)을 가진 두 번째 파일이므로, 참조 도메인과 별도로 검토하세요. 각 실행은 저렴하고 반복 가능해야 합니다. 이것이 핵심 아이디어입니다.
실행 로그 읽기
첫 번째 실행의 로그를 열어보세요. 일정을 신뢰하기 전에 하세요. 행 수, 잔액 및 커밋 줄을 확인하세요. 세 항목 중 하나가 누락되면 해당 작업이 주장한 것보다 적은 작업을 수행했다는 의미입니다. 매월 지출액을 대시보드 없이 확인할 수 있도록 각 실행 시 잔액에 대한 짧은 메모도 유지하세요.
초록색 체크는 거의 알려주는 것이 없습니다. 이는 프로세스가 깔끔하게 종료되었음을 의미할 뿐, 파일에 올바른 행이 포함되어 있는지(그래서 스크립트가 자체 요약을 출력하는 이유)는 알려주지 않습니다. 스크립트 버전 간에 이러한 요약 줄을 변경하지 마세요. 그래야 두 로그의 차분이 실제 변경 사항만 보여줍니다.
건강한 로그의 모습
건강한 실행은 행 수와 크레딧 잔액을 나타내는 한 줄과 오늘 날짜의 커밋을 출력합니다. 이러한 줄이 추가적인 노이즈 아래에 묻히는 것은 두 번 살펴볼 가치가 있습니다.
조용한 실패 감지
빈 폴더, 나타나지 않는 커밋 또는 총 행 수와 다른 행 수를 주의 깊게 관찰하세요. 이러한 현상은 API 자체가 아닌 루프 또는 파싱 문제를 가리킵니다. 나중에 비교할 수 있도록 첫 번째 건강한 로그를 참조용으로 저장하세요.
일부 실패는 평소보다 행 수가 적은 폴더를 남깁니다. 녹색 실행을 축하하기 전에 이전 주와의 수를 비교하세요. 조용한 잘림(truncation)은 조용한 월과 정확히 동일해 보일 수 있기 때문입니다.
두 번째 타겟 안전하게 추가
두 번째 도메인은 전체 워크플로우의 복사가 아닌 행렬 항목입니다. 각 대상에 고유한 작업을 부여하여 하나의 실패가 다른 실패를 숨기지 않도록 하세요. 각 작업을 분리하세요. 경로에 도메인 이름이 포함되어 있어 두 실행이 동일한 파일에 쓰지 않도록 확인하세요.
먼저 두 번째 타겟 alone로 시작하세요. 폴더가 올바르게 보이면 나머지 작업을 추가하세요. 중간에 실패하는 행렬은 두 개의 단순한 실행보다 읽기 어렵습니다.
타겟별로 폴더 이름 지정
경로에 도메인을 넣으세요(예: data/<domain>/YYYY-MM-DD). 그러면 두 작업이 같은 분에 실행되어도 폴더가 분리됩니다. 오래된 폴더는 경로에 날짜가 포함되어 있어 찾기 쉽기 때문에 원래 위치에 그대로 두어도 됩니다.
모든 타겟에 동일한 명명 규칙을 사용하세요. 그러면 스크립트가 특수 케이스 없이 폴더를 나열할 수 있습니다.
크레딧 예산 먼저 계획하기
타겟당 호출 횟수에 타겟 수를 곱한 후, 첫 번째 실행 전에 총량이 잔액과 비교 가능한지 확인하세요. 행렬은 작업을 곱하는 속도로 지출도 곱합니다. 워크플로우 옆에 예상 월 총액을 저장소에 기록하세요. 잔액이 예상보다 빠르게 떨어지면 루프가 페이지를 다시 가져오고 있을 가능성이 높으므로 다음 실행 전에 중단할 수 있습니다.
첫 주에 자주 묻는 질문
개인 저장소에서 무료로 실행할 수 있나요?
일반적으로 가능합니다. 월간 무료 분량 내에서요. 스냅샷 작업은 1분도 채 걸리지 않으므로 주간 일정은 아주 작은 분량을 사용합니다. GitHub은 때때로 할당량을 변경하므로 현재 자신의 플랜 할당량을 확인하세요.
여러 사람이 푸시할 경우 키를 어디에 저장해야 하나요?
조직 또는 저장소 시크릿에 저장하세요. 파일에는 저장하지 마세요. 워크플로우를 편집할 수 있는 사람은 누구나 로그에 시크릿을 출력할 수 있으므로 쓰기 권한이 있는 사람을 제한하고, 누군가 프로젝트에서 떠나면 키를 교체하세요.
스케줄된 실행이 왜 실행되지 않았나요?
세 가지 일반적인 이유가 있습니다. 워크플로우 파일이 기본 분기에 없거나, 저장소가 60일 동안 비어 있어 GitHub이 일정을 일시 중단했거나, cron 문자열에 오타가 있습니다. 스크립트 자체를 제외하기 위해 workflow_dispatch로 한 번 실행하세요.
데이터 폴더는 얼마나 커지나요?
작습니다. 참조 도메인 1,000개는 JSON 형식으로 몇백 킬로바이트에 불과합니다. 한 도메인의 주간 파일 1년 치는 100메가바이트 미만으로 유지되므로 git에 적합합니다. 불편하다면 오래된 폴더를 압축할 수 있습니다.