Manual de operațiuni

Instantanee săptămânale ale backlinkurilor cu GitHub Actions: un manual de operațiuni

Obiectiv: în fiecare luni, un flux de lucru scrie domeniile care fac referire și anchor textele din ziua respectivă în repo. Nimic altceva. Compararea (diffing) vine mai târziu.

Pod de fier peste un râu, simbolizând infrastructura fiabilă a fluxului de lucru programat
Înainte de a începe

Ai nevoie de un repo, o cheie Linkzoid stocată ca secretul LZ_KEY și un domeniu deținut de tine. Buget: aproximativ 6 credite pe țintă per execuție, adică $0.0006. Un instantaneu este o constatare pentru o lună, deci execuțiile săptămânale vor reîncărca în mare parte același index. Configurarea modului de verificare a backlinkurilor către site-ul meu în acest fel necesită o seară.

Manualul de operațiuni, în ordine

01

1. Adaugă secretul

Setări repo, apoi Secrets and variables, apoi Actions. Denumește-l LZ_KEY. Dacă îl lipești în fișierul workflow, rotirea cheii trebuie făcută azi.

02

2. Commită scriptul

Salvează Pythonul de mai jos ca snap.py. Acesta scrie data/YYYY-MM-DD/refdomains.json și eșuează la orice răspuns unde ok este false.

03

3. Commită workflow-ul

Folosește YAML-ul de mai jos. Rulează-l o dată manual cu trigger-ul workflow_dispatch și citește logul înainte de a avea încredere în programare.

04

4. Verifică primul fișier

Deschide JSON-ul. Confirmă numărul de rânduri împotriva total și compară numărul cu ceea ce raportează apelul gratuit overview pentru domeniul tău.

05

5. Adaugă alertarea

Un job eșuat trimite un email proprietarului repo implicit. Lasă asta activ. Un job care se oprește liniștit este de obicei modul în care aceste configurații mor.

snap.py

Biblioteca standard. Bucla se termină la numărul de înregistrări, niciodată pe baza unei presupuneri.

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

Cron-ul în GitHub rulează în UTC și poate începe târziu când runner-ele sunt ocupate. Nu construi nimic care depinde de minut.

yaml
name: backlink-snapshot
on:
  schedule:
    - cron: '17 6 * * 1'
  workflow_dispatch:
jobs:
  snap:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: python snap.py example.com
        env:
          LZ_KEY: ${{ secrets.LZ_KEY }}
      - run: |
          git config user.name snapshot-bot
          git config user.email "snapshot-bot@localhost"
          git add data
          git commit -m "snapshot $(date -u +%F)" || exit 0
          git push
Grădinar tuns un puieț, reprezentând pregătirea înainte de a începe programarea

Înainte de a activa programarea

  • Cheia stă în repository secrets, iar YAML-ul doar o referă prin nume.
  • Fișierul workflow este pe branch-ul default, deoarece acesta este copia pe care o citește programarea.
  • O execuție manuală cu workflow_dispatch s-a terminat și a scris un dosar datat.
  • Numărul de rânduri din fișier se potrivește cu totalul returnat de API pentru acel apel.
  • Jobul iese cu cod non-zero la un răspuns greșit, astfel încât un eșec face ca execuția să fie roșie.

Greșeli și remedieri

Ce se strică primul într-un job programat de backlinkuri
GreșealăCe veziRemediere
Cheia lipită în YAMLCheie vizibilă în istoricul repoRotire cheie, mutare în secrets.LZ_KEY
Minut ciudat precum 0 0Execuția începe cu 20 de minute întârziereAlege 17 6; vârful de oră este aglomerat
Repo inactiv timp de 60 de zileGitHub pune în pauză programareaFă un commit sau re-activare în tabul Actions
Bucla se oprește doar la o pagină goalăExecuție infinită la capul de paginăOprește-te și când len(rows) >= total
Codul de ieșire ignoratBifă verde, dosar golFolosește sys.exit pe ok: false
Commitul eșuează dacă nu sunt modificăriExecuție roșie degeabaAdaugă || exit 0 după commit

Menținerea cheii și a repo-ului în siguranță

Cheia este singurul lucru din această configurație care merită protejat. Trateaz-o ca pe o parolă, deoarece oricine deține cheie poate cheltui soldul tău.

Joburile programate scapă chei liniștit. O cheie lipită într-un log, un workflow copiat într-un repo public sau un fost coleg cu acces de scriere sunt căile uzuale. Verifică fiecare o dată pe trimestru.

Rotirea cheii când cineva pleacă

Când un coleg cu acces pleacă, creează o cheie nouă, actualizează secretul și retrage pe cel vechi. Apoi confirmă că următoarea execuție trece. O singură execuție verde după modificare este cel mai ieftin test pe care îl vei face în tot anul. Scrie data rotirii în notele repo-ului, astfel încât următoarea rotire să nu fie o surpriză.

Limitează pe cine poate edita workflow-ul

Oricine poate edita YAML-ul poate tipări secretul într-o execuție. Menține accesul de scriere scurt și revizuiește modificările la fișierul workflow așa cum revizuiești codul. Două persoane cu acces de scriere sunt de obicei suficiente pentru un repo mic.

Nu tipă niciodată URL-ul cererii

Tipărește soldul și numărul de rânduri, niciodată URL-ul cererii. Cheia circulă în șirul de interogare, deci o linie de debug care tipărește URL-ul scrie cheia în log. Dacă trebuie să partajezi o cerere într-o problemă, înlocuiește mai întâi cheia cu un placeholder.

Busolă și plantă în ghiveci, indicând progresul constant și detectarea timpurie a problemelor

Ce este instantaneul și ce nu este

Ceea ce primești este o imagine lunară. Crawler-ul nostru actualizează indexul aproximativ o dată pe lună, deci două execuții de luni în aceeași lună returnează adesea aceleași rânduri. Acesta este un lucru normal.

Un ritm săptămânal funcționează. Menține obiceiul viu și prinde un job eșuat în șapte zile în loc de treizeci. Dacă un link construit marți lipsește luni, așteaptă următoarea actualizare înainte de a te alarma.

Când ai trei sau patru dosare datate, treci la difuzarea SQLite. Dacă ești blocat de un cod de răspuns încăpățânat, tabelul de limitare a ratelor listează ce înseamnă fiecare status pentru o buclă.

Păstrează primul dosar ca bază. Fiecare comparație ulterioară se întoarce la el, iar un dosar numit după dată este mult mai ușor de încredere decât o amintire despre cum arătau numerele vara trecută. Fii consecvent.

Adăugarea anchor textelor și a paginilor top

O acțiune per fișier menține diff-urile lizibile. Copiază bucla din snap.py, schimbă refdomains în anchors sau toppages și scrie într-un al doilea nume de fișier. Fiecare costă 2 credite.

Un fișier combinat ascunde care parte s-a schimbat, iar un reviewer care derulează un pull request vrea să vadă un concept per diff. Ține-le separate. Dacă urmărești trei domenii, buclează peste o listă scurtă în workflow cu o matrice, astfel încât fiecare țintă să aibă propriul job și propria eroare.

Anchor textele sunt un al doilea fișier cu propriul cap în diff, astfel încât revizuiește-le separat de domeniile care fac referire. Fiecare execuție rămâne ieftină și repetabilă, acesta fiind ideea de bază.

Citirea logului de execuție

Deschide logul primei execuții. Fă-o înainte de a avea încredere în programare. Caută numărul de rânduri, soldul și linia de commit. Dacă oricare dintre cele trei lipsește, jobul a făcut mai puțin decât pretinde. Ține și un scurt note al soldului la fiecare execuție, astfel încât cheltuiala lunară să fie vizibilă fără a deschide dashboard-ul.

O bifă verde spune puțin. Înseamnă doar că procesul a ieșit curat. Nu spune că fișierul conține rândurile corecte, de aceea scriptul își tipărește propriul sumar. Păstrează acele linii de sumar neschimbate între versiunile scriptului, astfel încât un diff al două loguri să arate doar modificări reale.

Cum arată un log sănătos

O execuție sănătoasă tipărește o linie cu numărul de rânduri și soldul de credite, apoi un commit cu data de azi. Orice îngroapă acele linii sub zgomot suplimentar merită o a doua privire.

Detectarea unui eșec tăcut

Urmărește un dosar gol, un commit care nu apare niciodată sau un număr de rânduri care diferă de total. Fiecare dintre acestea indică bucla sau parsarea, nu API-ul în sine. Salvează primul log sănătos ca referință pentru comparațiile viitoare.

Unele eșecuri lasă în urmă un dosar cu mai puține rânduri decât de obicei. Compară numărul cu săptămâna precedentă înainte de a sărbători o execuție verde, deoarece o trunchiere liniștită arată exact ca o lună liniștită.

Adăugarea unei a doua ținte în siguranță

Un al doilea domeniu este o intrare matrice, nu o copie a întregului workflow. Dă fiecărei ținte propriul job astfel încât un eșec să nu ascundă altul. Menține fiecare job separat. Verifică că căile includ numele domeniului, astfel încât două execuții să nu scrie niciodată în același fișier.

Începe doar cu a doua țintă. Odată ce dosarul arată corect, adaugă restul. O matrice care eșuează pe jumătate este mai greu de citit decât două execuții simple.

Numirea dosarelor după țintă

Pune domeniul în cale, de exemplu data/<domain>/YYYY-MM-DD, și dosarele rămân separate chiar și când două joburi rulează în același minut. Dosarele vechi pot rămâne unde sunt, deoarece o dată în cale le face ușor de găsit.

Folosește aceeași regulă de numire pentru fiecare țintă. Un script poate apoi să listeze dosarele fără cazuri speciale.

Planifică bugetul de credite mai întâi

Înmulțește apelurile pe țintă cu numărul de ținte, apoi verifică totalul împotriva soldului înainte de prima execuție. O matrice multiplică cheltuiala la fel de repede pe cât multiplică joburile. Scrie totalul lunar așteptat în repo lângă workflow. Când soldul scade mai repede decât atât, o buclă probabil reîncarcă pagini și poți opri înainte de următoarea execuție.

Întrebări care apar în prima săptămână

Pot rula asta pe un repo privat gratuit?
De obicei da, în limitele minutelor lunare pe care GitHub le oferă conturilor gratuite. Un job de instantaneu rulează în mult sub un minut, deci o programare săptămânală folosește o fracțiune mică. Verifică allowance-ul curent al planului tău, deoarece GitHub îl schimbă din când în când.
Unde ar trebui să trăiască cheia dacă mai multe persoane fac push?
Într-un secret de organizație sau repository, niciodată în fișiere. Oricine poate edita workflow-ul poate tipări un secret într-un log, deci limitează pe cine are acces de scriere și rotește cheia dacă cineva părăsește proiectul.
De ce nu s-a declanșat execuția programată?
Trei motive uzuale. Fișierul workflow nu este pe branch-ul default, repo a fost inactiv timp de 60 de zile și GitHub a pus în pauză programarea, sau șirul cron are o greșeală de tastare. Rulează-l o dată cu workflow_dispatch pentru a exclude scriptul în sine.
Cât de mari devin dosarele de date?
Mici. O mie de domenii care fac referire este câteva sute de kilobyți de JSON. Un an de fișiere săptămânale pentru un domeniu rămâne mult sub o sută de megabytes, ceea ce este bine pentru git, deși poți comprima dosarele mai vechi dacă te deranjează.