背景・課題
| 課題 |
内容 |
gaurav-nelson/github-action-markdown-link-check が事実上開発停止 |
上流の tcort/markdown-link-check (npm) のラッパーだが wrapper 固有のバグが放置されている |
| 誤検出が多い |
並列度制御が弱く、短時間に大量リクエストを送信 → 対象サーバーが 429/403 を返し「dead」と誤検出 |
| DDoS 懸念 |
毎日フルスキャンで約 9,600 件の HTTP リクエストを送信 |
移行先
lycheeverse/lychee-action (lychee v0.x / Rust製)
- Rust 製で高速・軽量
- 並列数・リトライ間隔・キャッシュを細かく設定可能
- GitHub Actions cache を使った結果キャッシュをネイティブサポート
- 活発にメンテナンスされている(2025 年も定期リリース)
設計方針
負荷軽減
| 施策 |
設定値 |
効果 |
| 並列数を絞る |
--max-concurrency 8 |
同時に飛ばすリクエストの上限を 128 → 8 に制限。単一サーバーへの同時接続数が減り、スループット(単位時間あたりのリクエスト数)が下がる。リクエスト間に固定の間隔が入るわけではなく、空きスロットができ次第即座に次を送る仕組み |
| キャッシュ有効化 |
--cache --cache-max-age 14d |
2 回目以降は新規 URL のみチェック |
| 403 ドメインを除外 |
lychee.toml の exclude リスト |
リクエスト自体を送らない(後述) |
| 定期実行を週1回に変更 |
cron: "30 15 * * 0" (日曜 0:30 JST) |
毎日 → 週1回 |
誤検出対策
| 施策 |
設定値 |
効果 |
429 (Rate Limited) を許容 |
--accept 429 |
Rate limit 応答を dead とみなさない |
| リトライ間隔を設ける |
--retry-wait-time 3 |
失敗後 3 秒待ってリトライ |
| リトライなし |
--max-retries 0 |
週次実行+14日キャッシュの構成では、今週の誤検出は来週自然にクリアされる。--accept 429 と exclude で主要な誤検出原因は既に対処済みのため、リトライは不要 |
相対パス(./, ../)の扱い:除外せずチェックする
mlc_config.json では ./ と ../ で始まる相対リンクを ignorePatterns で除外していた。
lychee ではこれらを exclude に入れない。理由:
- lychee は相対パスをファイルの所在ディレクトリ基準でローカルファイルとして解決できる
- ファイルが存在すればチェック通過、存在しなければ失敗 → 内部リンク切れを検出できる
markdown-link-check が相対パス解決に不安定だったため除外していたが、lychee では不要なワークアラウンド
403 ドメインの扱い:--accept 403 ではなく --exclude を使う
現行の mlc_config.json の ignorePatterns は、403 を返すドメインのリストです。
--accept 403(リクエストを送った上でエラー扱いしない)ではなく、exclude(リクエスト自体を送らない)を使うべき理由:
403 Forbidden = サーバーが自動アクセスを明示的に拒否している
--accept 403 は拒否している相手にリクエストを送り続けることになり、先方の意向に反する
exclude にすることで、リクエスト数も減らせる
429 Too Many Requests とは性質が異なる:
| ステータス |
意味 |
正しい対処 |
429 |
「今は混んでいる、少し待って」 |
--accept 429 で許容し、次回チェック時に再確認 |
403 |
「あなたのアクセスを拒否します」 |
exclude でリクエスト自体を送らない |
mlc_config.json → lychee.toml の移行
現行の除外ドメイン(mlc_config.json の ignorePatterns)を lychee.toml の exclude に移行する。
CLI フラグではなく設定ファイルにまとめることで、ワークフロー YAML が肥大化しない。
gaurav-nelson との互換性について
| 項目 |
gaurav-nelson |
lychee |
| 設定ファイル |
mlc_config.json (JSON) |
lychee.toml (TOML) |
use-quiet-mode |
'yes' |
--quiet |
use-verbose-mode |
'yes' |
--verbose |
check-modified-files-only |
'yes' |
tj-actions/changed-files で変更ファイル一覧を取得し、lychee の引数として渡す |
ignorePatterns |
mlc_config.json |
lychee.toml の exclude |
retryOn429 |
true |
accept = ["429"] |
fallbackRetryDelay |
"75s" |
retry_wait_time = 3(秒) |
retryCount |
2 |
max_retries = 0(リトライなし) |
設定ファイル形式は互換性なし。ただし lychee.toml で同等以上の設定を再現できる。
背景・課題
gaurav-nelson/github-action-markdown-link-checkが事実上開発停止tcort/markdown-link-check(npm) のラッパーだが wrapper 固有のバグが放置されている429/403を返し「dead」と誤検出移行先
lycheeverse/lychee-action(lychee v0.x / Rust製)設計方針
負荷軽減
--max-concurrency 8--cache --cache-max-age 14dlychee.tomlのexcludeリストcron: "30 15 * * 0"(日曜 0:30 JST)誤検出対策
429(Rate Limited) を許容--accept 429--retry-wait-time 3--max-retries 0--accept 429とexcludeで主要な誤検出原因は既に対処済みのため、リトライは不要相対パス(
./,../)の扱い:除外せずチェックするmlc_config.jsonでは./と../で始まる相対リンクをignorePatternsで除外していた。lychee ではこれらを
excludeに入れない。理由:markdown-link-checkが相対パス解決に不安定だったため除外していたが、lychee では不要なワークアラウンド403 ドメインの扱い:
--accept 403ではなく--excludeを使う現行の
mlc_config.jsonのignorePatternsは、403を返すドメインのリストです。--accept 403(リクエストを送った上でエラー扱いしない)ではなく、exclude(リクエスト自体を送らない)を使うべき理由:403 Forbidden= サーバーが自動アクセスを明示的に拒否している--accept 403は拒否している相手にリクエストを送り続けることになり、先方の意向に反するexcludeにすることで、リクエスト数も減らせる429 Too Many Requestsとは性質が異なる:429--accept 429で許容し、次回チェック時に再確認403excludeでリクエスト自体を送らないmlc_config.json→lychee.tomlの移行現行の除外ドメイン(
mlc_config.jsonのignorePatterns)をlychee.tomlのexcludeに移行する。CLI フラグではなく設定ファイルにまとめることで、ワークフロー YAML が肥大化しない。
gaurav-nelson との互換性について
mlc_config.json(JSON)lychee.toml(TOML)use-quiet-mode'yes'--quietuse-verbose-mode'yes'--verbosecheck-modified-files-only'yes'tj-actions/changed-filesで変更ファイル一覧を取得し、lychee の引数として渡すignorePatternsmlc_config.jsonlychee.tomlのexcluderetryOn429trueaccept = ["429"]fallbackRetryDelay"75s"retry_wait_time = 3(秒)retryCount2max_retries = 0(リトライなし)設定ファイル形式は互換性なし。ただし
lychee.tomlで同等以上の設定を再現できる。