Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/outer_link_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ jobs:
- name: check
run: |
{ python3 .github/workflows/script/link_check.py --check-outer-link 3>&2 2>&1 1>&3 | tee check_result.txt; } 3>&2 2>&1 1>&3
- name: recheck if the first check reported failures
# 1回目が失敗を報告した場合のみ、時間をあけてもう一度チェックし直す。
# ランナー側のネットワーク不調など、1回の実行がまるごと一時障害に当たった
# ケースを誤検出しないためのワークフローレベルの再チェック。
# 2回目の結果でcheck_result.txtを上書きし、両方で失敗したものだけを通知する。
run: |
if [ -s check_result.txt ]; then
echo "First check reported failures. Waiting 5 minutes and rechecking to rule out transient/runner-side issues."
sleep 300
{ python3 .github/workflows/script/link_check.py --check-outer-link 3>&2 2>&1 1>&3 | tee check_result.txt; } 3>&2 2>&1 1>&3
fi
- name: create github issue when needed
run: python3 .github/workflows/script/create_github_issue_when_not_empty.py check_result.txt ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }} ${{ github.sha }}
- name: detect link check check_result
Expand Down
68 changes: 51 additions & 17 deletions .github/workflows/script/link_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,49 @@
import sys
import time
import random
from concurrent.futures import ThreadPoolExecutor

urllib3.disable_warnings()

def retry_sleep():
sec = random.uniform(20, 30)
time.sleep(sec)
# 外部リンクチェックの並列数。ネットワークI/OバウンドなのでスレッドでOK。
# open-std.org (全URLの過半) が同時16接続を問題なく捌けることを実測して決定。
OUTER_LINK_WORKERS = 16

def check_url(url: str, retry: int = 5) -> tuple[bool, str]:
MAX_OUTER_LINK_RETRY = 3

def retry_sleep(retry: int) -> None:
# 指数バックオフ + ジッタ。残りretry回数から試行回数を求めて待機時間を増やし、
# ジッタで再試行タイミングを分散させる (レート制限中のサーバへの集中を避ける)。
attempt = MAX_OUTER_LINK_RETRY - retry + 1 # 1, 2, 3, ...
backoff = min(15 * (2 ** (attempt - 1)), 60) # 15, 30, 60 秒 (上限60秒)
time.sleep(backoff + random.uniform(0, 15)) # 0〜15秒のジッタ

def check_url(url: str, retry: int = MAX_OUTER_LINK_RETRY) -> tuple[bool, str]:
try:
headers = {'User-agent': 'Mozilla/5.0'}
res = requests.head(url, headers=headers, verify=False, timeout=60.0)
if res.url:
if res.url == url:
return res.status_code != 404, "404"
return check_url(res.url)
else:
return res.status_code != 404, "404"
# パフォーマンスのため本文は取得せずHEADで確認する。
# ただしallow_redirects=Trueでリダイレクトはrequestsに追わせ、最終的な
# ステータスで判定する (手動でres.urlを辿る再帰をやめ、リトライ回数が
# 途中でリセットされる問題を避ける)。
res = requests.head(url, headers=headers, verify=False, timeout=60.0,
allow_redirects=True)
return res.status_code != 404, str(res.status_code)
except requests.exceptions.TooManyRedirects:
# リダイレクトループ (http↔httpsを行き来する等)。ブラウザではHSTS等で
# 到達できることが多く、リトライしても解消しないため、存在するものとして
# 扱う (ループ誤検出とムダな再試行を避ける)。
# ※ TooManyRedirectsはRequestExceptionのサブクラスなので、下の汎用ハンドラ
# より前で捕捉する必要がある。
return True, "redirect loop"
except requests.exceptions.ConnectionError as e:
if retry <= 0:
return False, "requests.exceptions.ConnectionError : {} ".format(e)
retry_sleep()
retry_sleep(retry)
return check_url(url, retry - 1)
except requests.exceptions.RequestException as e:
if retry <= 0:
return False, "requests.exceptions.RequestException : {}".format(e)
retry_sleep()
retry_sleep(retry)
return check_url(url, retry - 1)
except Exception as e:
return False, "unknown exception : {}".format(e)
Expand Down Expand Up @@ -169,11 +186,28 @@ def check(check_inner_link: bool, check_outer_link: bool, url: str) -> bool:
if len(url) > 0:
outer_link_dict[url] = ""

for link, from_list in outer_link_dict.items():
def check_one(item):
link, from_list = item
exists, reason = check_url(link)
if not exists:
print("URL {} not found. {} from:{}".format(link, reason, from_list), file=sys.stderr)
found_error = True
return link, from_list, exists, reason

# 1パス目: 失敗したURLだけ集める (ネットワークI/Oバウンドなのでスレッドで並列化)
failed = []
with ThreadPoolExecutor(max_workers=OUTER_LINK_WORKERS) as executor:
for link, from_list, exists, reason in executor.map(check_one, outer_link_dict.items()):
if not exists:
failed.append((link, from_list))

# 2パス目: 一時的な障害 (ランナーのネットワーク輻輳やサイトの瞬断) を
# 誤検出しないよう、間をあけて失敗したURLのみ再チェックし、
# 両方のパスで失敗したものだけを報告する
if failed:
time.sleep(120)
with ThreadPoolExecutor(max_workers=OUTER_LINK_WORKERS) as executor:
for link, from_list, exists, reason in executor.map(check_one, failed):
if not exists:
print("URL {} not found. {} from:{}".format(link, reason, from_list), file=sys.stderr)
found_error = True

return not found_error

Expand Down
2 changes: 1 addition & 1 deletion lang/cpp17/extending_static_assert.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ example_static_assert.cpp:5:3: error: static_assert failed
## この機能が必要になった背景・経緯
`assert` は条件式のみを引数に取るのに対し、`static_assert` には診断メッセージを提供しなければならなかった。

[Boost.StaticAssert](http://www.boost.org/doc/libs/release/doc/html/boost_staticassert.html) は以下のような `BOOST_STATIC_ASSERT` マクロを提供しており、
[Boost.StaticAssert](https://www.boost.org/doc/libs/latest/libs/config/doc/html/index.html) は以下のような `BOOST_STATIC_ASSERT` マクロを提供しており、
`static_assert` の診断メッセージを省略できた:
```cpp
#define BOOST_STATIC_ASSERT(B) static_assert(B, #B)
Expand Down
2 changes: 1 addition & 1 deletion reference/random/bernoulli_distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,4 @@ int main()

## 参照
- [ベルヌーイ分布 - Wikipedia](https://ja.wikipedia.org/wiki/ベルヌーイ分布)
- [ベルヌーイ分布(Bernoulli distribution) - NtRand](http://www.ntrand.com/jp/bernoulli-distribution/)
- [ベルヌーイ分布(Bernoulli distribution) - NtRand](https://www.ntrand.com/ja/docs/gallery-of-distributions/bernoulli-distribution)
2 changes: 1 addition & 1 deletion reference/random/cauchy_distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,4 @@ int main()

### 参考
- [コーシー分布 - Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%82%B7%E3%83%BC%E5%88%86%E5%B8%83)
- [コーシー分布 - NtRand](http://www.ntrand.com/jp/cauchy-distribution/)
- [コーシー分布 - NtRand](https://www.ntrand.com/ja/docs/gallery-of-distributions/cauchy-distribution)
2 changes: 1 addition & 1 deletion reference/random/exponential_distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,6 @@ Phone call after 2.60918 minute wait

### 参考
- [指数分布 - Wikipedia](https://ja.wikipedia.org/wiki/指数分布)
- [指数分布 - NtRand](http://www.ntrand.com/jp/exponential-distribution/)
- [指数分布 - NtRand](https://www.ntrand.com/ja/docs/gallery-of-distributions/exponential-distribution)
- [指数分布 - 統計学自習ノート](https://web.archive.org/web/20241204102039/http://aoki2.si.gunma-u.ac.jp/lecture/Bunpu/exponential.html)
- [指数分布とポアソン分布のいけない関係](http://www.slideshare.net/teramonagi/ss-11296227)
1 change: 0 additions & 1 deletion reference/random/extreme_value_distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,3 @@ int main()
### 参考
- [極値分布](https://ja.wikipedia.org/wiki/極値分布)
- [一般化極値分布 - MATLAB & Simulink - MathWorks 日本](https://jp.mathworks.com/help/stats/generalized-extreme-value-distribution.html)
- [極値分布とその応用に関する研究](http://www.seto.nanzan-u.ac.jp/msie/gr-thesis/ms/2005/osaki/02mm042.pdf)
2 changes: 1 addition & 1 deletion reference/random/lognormal_distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,5 @@ int main()

### 参考
- [対数正規分布 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%AF%BE%E6%95%B0%E6%AD%A3%E8%A6%8F%E5%88%86%E5%B8%83)
- [対数正規分布 - NtRand](http://www.ntrand.com/jp/log-normal-distribution/)
- [対数正規分布 - NtRand](https://www.ntrand.com/ja/docs/gallery-of-distributions/log-normal-distribution)
- [対数正規分布の仕組み - 小人さんの妄想](http://d.hatena.ne.jp/rikunora/20100418/p1)
2 changes: 1 addition & 1 deletion reference/random/poisson_distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Month 12: 1 earthquake(s)
### 参考
- [ポワソン分布 - Wikipedia](https://ja.wikipedia.org/wiki/ポアソン分布)
- [ポアソン分布 - 統計・データ解析](https://okumuralab.org/~okumura/stat/poisson.html)
- [ポアソン分布 - NtRand](http://www.ntrand.com/jp/poisson-distribution/)
- [ポアソン分布 - NtRand](https://www.ntrand.com/ja/docs/gallery-of-distributions/poisson-distribution)
- [[データ分析]ポアソン分布 ~ 100年に1人の天才は何人現れる?:やさしい確率分布 - @IT](https://atmarkit.itmedia.co.jp/ait/articles/2407/11/news002.html)


Expand Down
2 changes: 1 addition & 1 deletion reference/random/weibull_distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,5 @@ int main()

### 参考
- [ワイブル分布 - Wikipedia](https://ja.wikipedia.org/wiki/ワイブル分布)
- [ワイブル分布 = NtRand](http://www.ntrand.com/jp/weibull-distribution/)
- [ワイブル分布 = NtRand](https://www.ntrand.com/ja/docs/gallery-of-distributions/weibull-distribution)
- [疲労や破壊現象とワイブル分布](http://web.archive.org/web/20220706102605/http://www.mogami.com/notes/weibull.html)
Loading