Veckovisa backlänksögonblicksbilder på GitHub Actions: en manual
Mål: varje måndag skriver ett workflow dagens hänvisande domäner och ankartexter till repo. Inget annat. Diffning kommer senare.
Linkzoids redaktionella team ·
Innan du börjar
Du behöver ett repo, en Linkzoid-nyckel lagrad som sekretessnyckeln LZ_KEY, och en domän som du äger. Budget: cirka 6 krediter per mål per körning, vilket är $0.0006. En ögonblicksbild är en fakta om en månad, så veckokörningar hämtar oftast samma index. Att sätta upp hur du kontrollerar backlänkar till min webbplats på detta sätt tar en kväll.
Manualen, i ordning
01
1. Lägg till sekretessnyckeln
Repo-inställningar, sedan Sekretess och variabler, sedan Actions. Döp den till LZ_KEY. Om du klistrar in den i workflow-filen istället, rotera nyckeln idag.
02
2. Commit-scriptet
Spara Pythonen nedan som snap.py. Den skriver data/YYYY-MM-DD/refdomains.json och misslyckas vid alla svar där ok är false.
03
3. Commit-workflowen
Använd YAML:n nedan. Kör den en gång manuellt med triggen workflow_dispatch och läs loggen innan du litar på schemat.
04
4. Kontrollera den första filen
Öppna JSON-filen. Bekräfta radantalet mot total, och jämför antalet med vad den gratis overview-anropet rapporterar för din domän.
05
5. Lägg till varningen
Ett misslyckat jobb e-postar repoägaren som standard. Låt det vara kvar. Ett jobb som tyst upphör är det vanliga sättet dessa installationer dör.
snap.py
Standardbibliotek. Loopen slutar på antalet, aldrig på en gissning.
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 i GitHub körs i UTC och kan starta sent när körningsmiljöerna är upptagna. Bygg inte något som beror på minuten.
Nyckeln ligger i repo-sekretessnycklarna, och YAML:n refererar bara till den med namn.
Workflow-filen ligger på grenen default, eftersom det är den kopia som schemat läser.
En manuell körning med workflow_dispatch avslutades och skrev en mapp med datum.
Radantalet i filen matchar totalen som API:et returnerade för det anropet.
Jobbet avslutas med icke-noll vid ett dåligt svar, så ett misslyckande gör körningen röd.
Misstag och lösningar
Vad som bryts först i ett schemalagt backlänksjobb
Misstag
Vad du ser
Lösning
Nyckel klistrad in i YAML
Nyckel synlig i repo-historik
Rotatera den, flytta den till secrets.LZ_KEY
Udda minut som 0 0
Körningen startar 20 minuter sent
Välj 17 6; toppen av timmen är trängd
Repo i viloläge i 60 dagar
GitHub pausar schemat
Commita något, eller aktivera om det i fliken Actions
Loopen slutar bara på en tom sida
Evig körning vid sidgränsen
Sluta också när len(rows) >= total
Exitkod ignoreras
Grönt kryss, tom mapp
Använd sys.exit på ok: false
Commit misslyckas vid ingen ändring
Röd körning för ingenting
Lägg till || exit 0 efter commiten
Att hålla nyckeln och repo säkra
Nyckeln är det enda i denna installation som är värt att skydda. Behandla den som ett lösenord, eftersom alla som har den kan spendera din balans.
Schemalagda jobb läcker tyst. En nyckel klistrad in i en logg, en workflow kopierad till ett offentligt repo, eller en tidigare kollega med skrivåtkomst är de vanliga vägarna. Kontrollera var och en en gång per kvartal.
Rotatera nyckeln när någon lämnar
När en kollega med åtkomst lämnar, skapa en ny nyckel, uppdatera sekretessnyckeln och pensionera den gamla. Bekräfta sedan att nästa körning går igenom. En grön körning efter ändringen är det billigaste testet du gör hela året. Skriv rotateringsdatumet i repominnen också, så att nästa rotation inte blir en överraskning.
Begränsa vem som kan redigera workflowen
Varje som kan redigera YAML kan skriva ut sekretessnyckeln i en körning. Håll skrivåtkomsten kort, och granska ändringar i workflow-filen på samma sätt som du granskar kod. Två personer med skrivåtkomst är vanligtvis nog för ett litet repo.
Skriv aldrig ut begärans URL
Skriv ut balansen och radantalet, aldrig begärans URL. Nyckeln färdas i query string, så en debug-rad som skriver ut URL:en skriver in nyckeln i loggen. Om du måste dela en begäran i ett issue, ersätt nyckeln med en platshållare först.
Vad ögonblicksbilden är, och inte är
Vad du får är en månatlig bild. Vår egen crawler uppdaterar indexet ungefär en gång i månaden, så två måndagskörningar under samma månad returnerar ofta samma rader. Det är förväntat.
En veckovig rytm fungerar. Den håller vanan vid liv, och du upptäcker ett misslyckat jobb inom sju dagar istället för trettio. Om en länk du byggde på tisdag saknas på måndag, vänta på nästa uppdatering innan du panikslår.
När du har tre eller fyra mappar med datum, gå vidare till SQLite-diffen. Om du fastnar på en envis svarskod, tabellen för hastighetsbegränsning listar vad varje status betyder för en loop.
Behåll den första mappen som baslinje. Varje senare jämföring pekar tillbaka på den, och en mapp döpt efter datum är mycket lättare att lita på än ett minne av hur siffrorna såg ut förra våren. Var konsekvent.
Att lägga till ankartexter och toppsidor
En åtgärd per fil håller diffar läsbara. Kopiera loopen i snap.py, ändra refdomains till anchors eller toppages, och skriv till en andra filnamn. Varje kostar 2 krediter.
En kombinerad fil döljer vilken del som ändrades, och en granskare som scrollar en pull request vill se ett koncept per diff. Håll dem separata. Om du spårar tre domäner, loopa över en kort lista i workflowen med en matris, så att varje mål får sitt eget jobb och sitt eget misslyckande.
Ankartexter är en andra fil med sin egen gräns i diffen, så granska dem separat från de hänvisande domänerna. Varje körning förblir billig och upprepbar, vilket är hela idén.
Att läsa körningsloggen
Öppra loggen från den första körningen. Gör det innan du litar på schemat. Titta på radantalet, balansen och commitraden. Om någon av de tre saknas, gjorde jobbet mindre än det påstår. Håll också en kort notering av balansen vid varje körning, så att månadens utgifter är synliga utan att öppna dashboarden.
Ett grönt kryss säger lite. Det betyder bara att processen avslutades ordentligt. Det säger inte att filen innehåller rätt rader, vilket är varför scriptet skriver ut sin egen sammanfattning. Håll dessa sammanfattningsrader oförändrade mellan versioner av scriptet, så att en diff av två loggar visar verkliga ändringar endast.
Hur en frisk logg ser ut
En frisk körning skriver ut en rad med radantalet och kreditbalansen, sedan en commit med dagens datum. Allt som begraver dessa rader under extra brus är värt en andra titt.
Att upptäcka ett tyst misslyckande
Titta efter en tom mapp, en commit som aldrig dyker upp, eller ett radantal som skiljer sig från totalen. Var och en av dessa pekar mot loopen eller parsningen, inte mot API:et i sig. Spara den första friska loggen som en referens för senare jämförelser.
Vissa misslyckanden lämnar en mapp kvar med färre rader än vanligt. Jämför antalet med föregående vecka innan du firar en grön körning, eftersom en tyst truncation ser exakt ut som en tyst månad.
Att lägga till ett andra mål säkert
En andra domän är en matrispost, inte en kopia av hela workflowen. Ge varje mål sitt eget jobb så att ett misslyckande inte döljer ett annat. Håll varje jobb separat. Kontrollera att sökvägarna inkluderar domännamnet, så att två körningar aldrig skriver till samma fil.
Börja med det andra målet ensam. När dess mapp ser rätt ut, lägg till resten. En matris som misslyckas mitt i är svårare att läsa än två enkla körningar.
Döp mappar efter mål
Lägg till domänen i sökvägen, till exempel data/<domain>/YYYY-MM-DD, och mapparna förblir separata även när två jobb körs under samma minut. Gamla mappar kan stanna där de är, eftersom ett datum i sökvägen gör dem lätta att hitta.
Använd samma namngivningsregel för alla mål. Ett script kan då lista mapparna utan specialfall.
Planera kreditbudgeten först
Multiplicera anropen per mål med antalet mål, kontrollera sedan totalen mot din balans innan den första körningen. En matris multiplicerar utgifterna lika snabbt som den multiplicerar jobben. Skriv det förväntade månadliga totala i repo bredvid workflowen. När balansen sjunker snabbare än det, loopar den troligen igenom sidor, och du kan stoppa den innan nästa körning.
Frågor som dyker upp under den första veckan
Kan jag köra detta på ett privat repo gratis?
Vanligtvis ja, inom de månatliga minuterna GitHub ger gratis konton. En snapshot-jobb körs på långt under en minut, så ett veckoschema använder en liten del. Kontrollera ditt eget plans nuvarande tilldelning, eftersom GitHub ändrar det från tid till annan.
Var ska nyckeln bo om flera personer pushar?
I en organisations- eller repositoriessekretessnyckel, aldrig i filerna. Varje som kan redigera workflowen kan skriva ut en sekretessnyckel i en logg, så begränsa vem som har skrivåtkomst, och rotera nyckeln om någon lämnar projektet.
Varför sköt min schemalagda körning inte?
Tre vanliga orsaker. Workflow-filen är inte på grenen default, repo var i viloläge i 60 dagar och GitHub pausade schemat, eller cron-strängen har ett stavfel. Kör den en gång med workflow_dispatch för att utesluta scriptet i sig.
Hur stora blir datamapparna?
Små. Tusen hänvisande domäner är några hundra kilobyte JSON. Ett år med veckovfiler för en domän förblir långt under hundra megabyte, vilket är bra för git, även om du kan komprimera äldre mappar om det stör dig.