ランブック

GitHub Actionsでの毎週バックリンクスナップショット:ランブック

目標:毎週月曜日にワークフローが今日の参照ドメインとアンカーテキストをリポジトリに書き込む。それ以外は何もしない。差分比較は後で実施する。

信頼できるスケジュールワークフローインフラストラクチャを象徴する、川に架かる鉄橋
開始前に

リポジトリ、シークレット LZ_KEY として保存されたLinkzoidキー、そしてあなたが所有するドメインが1つ必要です。予算:1回の実行あたりターゲットごとに約6クレジット、つまり$0.0006です。スナップショットは1ヶ月の事実を示すため、毎週の実行では主に同じインデックスを再フェッチすることになります。この方法で自分のウェブサイトのバックリンクを確認する方法を設定するには、1晩あれば十分です。

ランブックの手順

01

1. シークレットを追加する

リポジトリ設定、次に「シークレットと変数」、そして「Actions」を選択します。名前を LZ_KEY にしてください。もしワークフローファイルに貼り付けた場合は、今日キーを更新してください。

02

2. スクリプトをコミットする

以下のPythonコードを snap.py として保存してください。これは data/YYYY-MM-DD/refdomains.json に書き込み、ok がfalseのレスポンスで失敗します。

03

3. ワークフローをコミットする

以下のYAMLを使用してください。スケジュールを信頼する前に、workflow_dispatch トリガーで手動で1回実行し、ログを確認してください。

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で実行され、ランナーが混雑している場合は遅延する可能性があります。分に依存するものは構築しないでください。

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
スケジュール開始前の準備を表す、若い苗木を剪定する庭師

スケジュールを有効にする前に

  • キーはリポジトリのシークレットに保存され、YAMLでは名前だけで参照されます。
  • ワークフローファイルはデフォルトブランチにあり、スケジュールが読み取るコピーがそこにあるためです。
  • manual run with workflow_dispatchが完了し、日付付きのフォルダが1つ作成されました。
  • ファイル内の行数は、その呼び出しに対してAPIが返したtotalと一致します。
  • ジョブはエラーレスポンスで非ゼロの終了コードで終了するため、失敗すると実行が赤色になります。

ミスと修正

スケジュール済みバックリンクジョブで最初に壊れるもの
ミス発生する現象修正
キーがYAMLに貼り付けられているキーがリポジトリの履歴で可視化されているキーを更新し、secrets.LZ_KEY に移動する
不自然な分、例えば 0 0実行が20分遅れる17 6 を選択する。時分の頭は混雑している
リポジトリが60日間アイドル状態GitHubがスケジュールを一時停止する何かコミットするか、Actionsタブで再有効化する
空のページでのみループが停止するページ上限で無限ループlen(rows) >= total の場合も停止する
終了コードが無視される緑のチェック、空のフォルダok: false の際に sys.exit を使用する
変更がない場合にコミットが失敗する無駄な失敗(レッドラン)コミットの後に || exit 0 を追加する

キーとリポジトリの保護

このセットアップにおいて保護すべき唯一のものはキーです。パスワードのように扱ってください。キーを保持している人は誰でも残高を使用できるためです。

スケジュールジョブは静かにリークします。ログに貼り付けられたキー、公開リポジトリにコピーされたワークフロー、または書き込み権限を持つ元チームメイトが通常の原因です。1クォーターに1回、それぞれを確認してください。

メンバーが退出した際にキーを更新する

アクセス権を持つチームメイトが退出した場合は、新しいキーを作成し、シークレットを更新して古いキーを廃棄してください。その後、次の実行が成功することを確認してください。変更後のグリーンランは、1年で最もコストの低いテストです。次の更新がサプライズにならないよう、リポジトリのノートにも更新日付を記録してください。

ワークフローの編集権限を制限する

YAMLを編集できる人は誰でも、実行中にシークレットを出力できます。書き込み権限を短く保ち、ワークフローファイルへの変更はコードレビューと同様に確認してください。小規模なリポジトリでは、書き込み権限を持つ人が2人いれば通常十分です。

リクエストURLを絶対に出力しない

残高と行数を出力し、リクエストURLは出力しないようにしてください。キーはクエリ文字列に含まれるため、URLを出力するデバッグ行はキーをログに書き込みます。イシューでリクエストを共有する必要がある場合は、まずキーをプレースホルダーに置き換えてください。

着実な進捗と初期の問題検出を示す、コンパスと鉢植え

スナップショットとは何か、そして何ではないか

得られるのは月次の状況です。当社のクローラーはインデックスを月1回程度更新するため、同じ月の2回の月曜実行では同じ行が返されることがよくあります。これは想定内の動作です。

週次で実行するのが効果的です。習慣が維持され、失敗したジョブを30日後ではなく7日以内に検出できます。火曜日に構築したリンクが月曜日に欠落している場合、パニックになる前に次の更新を待ってください。

日付付きのフォルダが3〜4つになったら、SQLite差分に進んでください。頑固なレスポンスコードで詰まっている場合は、レート制限テーブルにループにおける各ステータスの意味が記載されています。

最初のフォルダをベースラインとして維持してください。その後の比較はすべてそれを指し示すため、去年の春の数値の記憶よりも、日付名付きのフォルダの方がはるかに信頼できます。一貫性を保ってください。

アンカーとトップページの追加

ファイルごとに1つのアクションにすることで差分を読みやすく保ちます。snap.pyのループをコピーし、refdomainsをanchorsまたはtoppagesに変更して、2つ目のファイル名に書き込んでください。それぞれに2クレジットかかります。

結合ファイルではどの部分が変わったかが不明瞭になり、プルリクエストをスクロールするレビュアーは、差分ごとに1つの概念だけを見たいと望みます。分離してください。3つのドメインを追跡する場合は、ワークフローで短いリストに対してループ処理するマトリックスを使用し、各ターゲットに固有のジョブと固有の失敗を持たせてください。

アンカーは差分で独自の上限を持つ2つ目のファイルであるため、参照ドメインとは別にレビューしてください。各実行は安価で再現可能であり、それが本来の目的です。

実行ログの読み方

最初の実行のログを開いてください。スケジュールを信頼する前にこれを行ってください。行数、残高、コミット行を探してください。これら3つのいずれかが欠けている場合、ジョブは主張したほど多くの処理を行っていません。残高を各実行ごとに短いノートとして記録し、ダッシュボードを開かずに月次の支出を確認できるようにしてください。

緑のチェックはほとんど何も示しません。それはプロセスが正常に終了したことを意味するだけで、ファイルに正しい行が含まれていることは示しません。そのため、スクリプトは独自のサマリーを出力します。スクリプトのバージョン間でこれらのサマリー行を変更せず、2つのログの差分が実際の差分のみを示すようにしてください。

健全なログの外観

健全な実行は、行数とクレジット残高を含む1行を出力し、その日の日付を含むコミットを行います。これらの行が余分なノイズに埋もれている場合は、再検討の価値があります。

静かな失敗の特定

空のフォルダ、コミットが現れない、または行数が合計と異なることを注意深く観察してください。これらすべてはAPI自体ではなく、ループまたはパーサーを指しています。後日の比較のために、最初の健全なログをリファレンスとして保存してください。

一部の失敗は、通常よりも行数の少ないフォルダを残します。グリーンランを祝う前に、前週とのカウントを比較してください。静かな切り捨ては、静かな月と全く同じように見えるためです。

2つ目のターゲットを安全に追加する

2つ目のドメインはワークフロー全体のコピーではなく、マトリックスエントリです。各ターゲットに固有のジョブを持たせ、1つの失敗が別の失敗を隠さないようにしてください。各ジョブを分離してください。パスにドメイン名が含まれていることを確認し、2つの実行が同じファイルに書き込まれないようにしてください。

2つ目のターゲットだけで始めてください。フォルダが正しく表示されたら、残りを追加してください。途中で失敗するマトリックスは、2つの単純な実行よりも読み取りが困難です。

ターゲットごとにフォルダ名を付ける

パスにドメインを含めてください(例: data/<domain>/YYYY-MM-DD)。これにより、2つのジョブが同じ分に実行されてもフォルダは分離されたままになります。古いフォルダはそのままにしておいても構いません。パスに日付が含まれているため、見つけるのが容易です。

すべてのターゲットに同じ命名規則を使用してください。これにより、スクリプトは特殊なケースなしでフォルダをリストできます。

クレジット予算を最初に計画する

ターゲットごとの呼び出し数をターゲット数で掛け、最初の実行前に合計を残高と比較してください。マトリックスはジョブ数を増やすのと同じ速さで支出を増やします。ワークフローの隣に予想される月次合計をリポジトリに記録してください。残高がそれよりも速く減少する場合、ループがページを再フェッチしている可能性があり、次の実行前に停止できます。

最初の週によく寄せられる質問

プライベートリポジトリで無料で実行できますか?
通常はいえ、GitHubが無料アカウントに提供する月次分で実行できます。スナップショットジョブは1分未満で完了するため、週次スケジュールはわずかなシェアしか使用しません。GitHubは時折割り当てを変更するため、ご自身のプランの現在の割り当てを確認してください。
複数人がプッシュする場合、キーはどこに保存すべきですか?
組織またはリポジトリのシークレットに保存し、ファイル内には保存しないでください。ワークフローを編集できる人は誰でもログにシークレットを出力できるため、書き込み権限を持つ人を制限し、誰かがプロジェクトから退出した場合はキーを更新してください。
スケジュール実行がトリガーされなかったのはなぜですか?
3つの一般的な理由があります。ワークフローファイルがデフォルトブランチにない、リポジトリが60日間アイドル状態だったためGitHubがスケジュールを一時停止した、またはcron文字列にタイプミスがある。スクリプト自体を除外するために、workflow_dispatchで1回実行してください。
データフォルダはどれくらい大きくなりますか?
小さくなります。参照ドメイン1000件はJSONで数百キロバイトです。1つのドメインの週次ファイル1年分は100メガバイト未満に収まり、gitにとって問題ありませんが、気になる場合は古いフォルダを圧縮することもできます。