管理画面
Windmill は Web の管理画面を同梱している。この配備ではそれがそのまま capture-scheduler の管理画面になる。別に何かを立てる必要はない。
スクリーンショットは全部この repo の実データ(今日の失敗 → 成功の run 履歴)で、
scripts/docs-shots.ts が撮った生成物。手で撮った絵は 1 枚も無い ——
スクリーンショットは UI の書き写しで、書き写しは腐るため。撮り直しの手順は
開発 を見ること。
http://127.0.0.1:8000| 既定 | 上書き | |
|---|---|---|
admin@windmill.dev |
WINDMILL_EMAIL |
|
| password | changeme |
WINDMILL_PASSWORD |
port は loopback に閉じてある。compose のコメントの通り、ここに届く者は workspace を作り替えられる —— schedule も webhook も secret も UI から 書き換えられるので、他のマシンには出さない。
ログインすると workspace を選ぶ。bootstrap が作った crawler を選ぶ。
ホーム —— sidebar が地図
Section titled “ホーム —— sidebar が地図”crawler に入ると sidebar が出る。このページで歩くのは Home / Runs /
Schedules / Variables / Resources の 5 つ。
UI でやってよいのは「見る」「1 回だけ手で起こす」「一時的に止める」まで。
恒久的な変更は repo を直して push する。 schedule の enabled も
daily.schedule.yaml に入っているので、UI で止めても次の windmill:push で
動き出す。同期が両方向とも削除であることは 開発 を見ること。
Runs —— まず履歴を読む
Section titled “Runs —— まず履歴を読む”クロールが動いたか / 失敗したかは、ここが最初の一枚。
Path が段の種類を表す —— f/waggle/crawl_level が flow 本体で、
crawl_host などはその中の段。daily の行は schedule が起こしたもの。
行をクリックすると詳細に入る。成功した crawl_level の run を開くと、
上に成否と所要時間、下に flow が受け取った入力(crawl_id・depth・
辿るべき URL の frontier)が並ぶ。
flow の中の 1 段(ここでは report_level)を開くと、その段だけの入力と結果が見える。
段は独立して動くので、どの段が何を受け取り何を返したかをここで追える。
失敗を掘る —— 実例 1 つ
Section titled “失敗を掘る —— 実例 1 つ”失敗は段ごとに違う場所で違う理由で起きる。Runs で段と error を見て、 中身は各サービスのログへ というのが掘り方。
report_level が capture-ledger の POST /api/crawls/…/pages に届かなかった
(Unable to connect・ConnectionRefused)。Runs が言うのはここまで —— どの段が・どの宛先に
(path の http://127.0.0.1:9/…)・何で落ちたか。宛先が API ではないので、原因は
u/admin/waggle_api_url の値の側に在る(この絵は、変数をわざと閉じた口に向けて撮った)。
宛先に届いたうえで 500 などを受け取ったなら、中身は capture-ledger のログにしか無い。
UI で分かるのは「どの段が・どの宛先に・何で落ちたか」で、原因の特定は宛先側に渡す、という切り分けになる。
crawl_host の失敗も同じ読み方をする。段ごと落ちるのは BrowserHive に 1 つも届かない
ときだけ(BrowserHive に届きません: … に口が全部並ぶ)。1 つの BrowserHive に断られた
(400 ValidationException: …、断られた項目つき)のは段の結果の中のそのページの失敗で、
クロールは続く。どちらでも、BrowserHive がその要求をどう扱ったかは BrowserHive のログに在る。
Flow と script —— 何をするものか
Section titled “Flow と script —— 何をするものか”f/waggle/crawl_level を開くと、flow の説明(capture-ledger が投げた 1 段を
処理して報告する / 1 段で終わる / 礼儀の 3 点 / per-key concurrency は CE では
効かない)と、受け取る引数が読める。ここに書いてある思想は
リンクを辿る と Windmill CE の裏付けそのもの。
flow が for-loop で各 host に対して呼ぶのが crawl_host の script。
「1 ホストぶんを逐次で取り込む」「単体で叩くものではない」と説明にある通り、
flow の部品で、単独で起こすものではない。
script のコードは UI の Edit でも repo の windmill/f/waggle/ でも読めるが、
正は repo。UI で直すと次の windmill:push で戻る。
Schedules —— いつ走るか
Section titled “Schedules —— いつ走るか”f/waggle/daily が唯一の schedule。cron 0 0 4 * * *(毎日 04:00
Asia/Tokyo)で trigger_crawl を起こす。右のトグルが enabled。
トグルで止めても、daily.schedule.yaml の enabled: true が正なので
次の windmill:push で戻る。 恒久的に止めるなら yaml を直して push する。
意味は いつ走るか を見ること。
Variables
Section titled “Variables”u/admin/* の変数。waggle_token は secret なので値がマスクされて出る
(••••)—— マスクされていること自体が「UI に token を晒していない」の証拠。
Resources は空のまま —— この repo はそこに何も置かない(v0.22 までは BrowserHive の
.proto の写しが States タブに居た)。
手で 1 回だけ起こす
Section titled “手で 1 回だけ起こす”trigger_crawl を開くと Run のフォームがある。schema の説明が日本語で読める
(waggle_url = コンテナから見た capture-api、token = dev issuer の JWT、
limit を省くと enabled な行を全部)。
ただし schema の default は UI からの実行にしか埋まらない(CE の罠。
Windmill CE を見ること)。schedule や webhook からの実行には
届かないので、daily は変数から値を渡している。
変数の台帳 —— どの script が何を入れるか
Section titled “変数の台帳 —— どの script が何を入れるか”windmill:push が入れるのは git にあるものだけ(script・flow・schedule)。
変数は別の script が入れる。ここを混同すると、push が緑なのに flow が最初の
getVariable で落ちる。
| 置き場 | 中身 | 入れる script |
|---|---|---|
u/admin/waggle_token |
capture-ledger への JWT (secret) | windmill:capture-ledger-token |
u/admin/waggle_api_url |
capture-ledger API の宛先(既定は default ネットワークの gateway) | 同上 |
u/admin/browserhive_endpoints |
BrowserHive の URL の JSON 配列。BrowserHive 1 つに 1 要素(既定 ["http://browserhive-1.capture-ledger:50051","http://browserhive-2.capture-ledger:50051"]) |
同上 |
u/admin/browserhive_tls_ca |
https:// の口のための CA(空 = 平文の http://) |
同上 |
u/admin/ts_compile_url |
ts-compile-service の宛先(既定 http://ts-compile.capture-scheduler:8080) |
同上 |
口は BrowserHive v12 から http(s):// の URL。crawl_host は v11 の host:port の形を
この変数の名前を挙げて断り、windmill:capture-ledger-token は変数に書く前に断る ——
.env に残った古い CAPTURE_LEDGER_BROWSERHIVE_ENDPOINTS は flow ではなく道具で止まる。
全部消えたときの復旧
Section titled “全部消えたときの復旧”windmill-db の volume を消すと、workspace・token・変数が全部消える。 復旧の順序(2026-09-11 に実測):
pnpm run windmill:bootstrap # workspace を作り直し、新しい token を出す # → 出た WINDMILL_TOKEN= を .env に貼り直す # → 続く 4 行を capture-ledger の .env の末尾に # 貼り直して、あちらの API を起こし直すpnpm run windmill:push # script / flow / schedulepnpm run windmill:capture-ledger-token # 変数 5 つcd ../capture-ledgerpnpm run fga:grant submitter windmill acme # windmill に acme のクロールを許可するcapture-ledger 側の OpenFGA も同時に消えていたら、許可を書く前に
fga:migrate → fga:deploy で store を作り直し、出てきた 2 つの ID を
あちらの .env に貼る。
コンテナを作り直すと bridge の subnet が変わりうる。 u/admin/waggle_api_url に入るのは、
windmill:capture-ledger-token を叩いた時点の default ネットワークの gateway なので、subnet が
変わったらやり直す。外れていると report の段が届かずに落ち(Unable to connect. Is the computer able to access the url?)、クロールは running のまま残る。届いているかは pnpm run doctor の
container→api が見る —— 変数の宛先の /healthz に、worker の中から問い合わせ、届かなければ
宛先をいまの gateway と比べて、古いのか API が 127.0.0.1 で待っているのかを言う。最後に
pnpm run doctor が全部 ✓ になり、pnpm run smoke が「撮れた」と言えば、復旧は終わり。
f/waggle/ という名前
Section titled “f/waggle/ という名前”repo は waggle → capture-ledger と改名したが、Windmill の folder は
f/waggle/ のまま。folder のパスは webhook URL の一部
(/api/w/crawler/jobs/run/f/f/waggle/crawl_level)で、変えると
capture-ledger 側に設定した webhook が壊れる。名前ではなく外部契約として
据え置いてある。