コンテンツにスキップ

管理画面

Windmill は Web の管理画面を同梱している。この配備ではそれがそのまま capture-scheduler の管理画面になる。別に何かを立てる必要はない。

スクリーンショットは全部この repo の実データ(今日の失敗 → 成功の run 履歴)で、 scripts/docs-shots.ts が撮った生成物。手で撮った絵は 1 枚も無い —— スクリーンショットは UI の書き写しで、書き写しは腐るため。撮り直しの手順は 開発 を見ること。

http://127.0.0.1:8000
既定 上書き
email admin@windmill.dev WINDMILL_EMAIL
password changeme WINDMILL_PASSWORD
Windmill のログイン画面。既定の資格情報が入力欄に補完されている

port は loopback に閉じてある。compose のコメントの通り、ここに届く者は workspace を作り替えられる —— schedule も webhook も secret も UI から 書き換えられるので、他のマシンには出さない。

ログインすると workspace を選ぶ。bootstrap が作った crawler を選ぶ。

workspace 選択画面。crawler と admins が並ぶ

crawler に入ると sidebar が出る。このページで歩くのは Home / Runs / Schedules / Variables / Resources の 5 つ。

crawler workspace のホーム。左に Home・Runs・Variables・Resources・Schedules の sidebar

UI でやってよいのは「見る」「1 回だけ手で起こす」「一時的に止める」まで。 恒久的な変更は repo を直して push する。 schedule の enabled も daily.schedule.yaml に入っているので、UI で止めても次の windmill:push で 動き出す。同期が両方向とも削除であることは 開発 を見ること。

クロールが動いたか / 失敗したかは、ここが最初の一枚。 Path が段の種類を表す —— f/waggle/crawl_level が flow 本体で、 crawl_host などはその中の段。daily の行は schedule が起こしたもの。

Runs の一覧。crawl_level の成功(緑)と失敗(赤)が時刻順に並ぶ

行をクリックすると詳細に入る。成功した crawl_level の run を開くと、 上に成否と所要時間、下に flow が受け取った入力(crawl_id・depth・ 辿るべき URL の frontier)が並ぶ。

成功した crawl_level の run 詳細。Successfully ran の帯と、frontier などの入力

flow の中の 1 段(ここでは report_level)を開くと、その段だけの入力と結果が見える。 段は独立して動くので、どの段が何を受け取り何を返したかをここで追える。

report_level の段の run 詳細。crawl_id と results の入力

失敗は段ごとに違う場所で違う理由で起きる。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 で分かるのは「どの段が・どの宛先に・何で落ちたか」で、原因の特定は宛先側に渡す、という切り分けになる。

report_level の失敗 run。Result に Unable to connect(ConnectionRefused、path は http://127.0.0.1:9/api/crawls/…/pages)

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 の裏付けそのもの。

crawl_level flow の詳細。説明文と Crawl Id・Depth・Frontier の入力

flow が for-loop で各 host に対して呼ぶのが crawl_host の script。 「1 ホストぶんを逐次で取り込む」「単体で叩くものではない」と説明にある通り、 flow の部品で、単独で起こすものではない。

crawl_host の script 詳細。flow の部品である旨の説明と入力仕様

script のコードは UI の Edit でも repo の windmill/f/waggle/ でも読めるが、 正は repo。UI で直すと次の windmill:push で戻る。

f/waggle/daily が唯一の schedule。cron 0 0 4 * * *(毎日 04:00 Asia/Tokyo)で trigger_crawl を起こす。右のトグルが enabled。

Schedules。f/waggle/daily の cron・タイムゾーン・有効トグル

トグルで止めても、daily.schedule.yaml の enabled: true が正なので 次の windmill:push で戻る。 恒久的に止めるなら yaml を直して push する。 意味は いつ走るか を見ること。

u/admin/* の変数。waggle_token は secret なので値がマスクされて出る (••••)—— マスクされていること自体が「UI に token を晒していない」の証拠。

Variables。waggle_token は値がマスク、他は browserhive_endpoints などが見える

Resources は空のまま —— この repo はそこに何も置かない(v0.22 までは BrowserHive の .proto の写しが States タブに居た)。

trigger_crawl を開くと Run のフォームがある。schema の説明が日本語で読める (waggle_url = コンテナから見た capture-api、token = dev issuer の JWT、 limit を省くと enabled な行を全部)。

trigger_crawl の Run フォーム。Waggle Url・Token・Limit の入力欄

ただし 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 ではなく道具で止まる。

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 / schedule
pnpm run windmill:capture-ledger-token # 変数 5 つ
cd ../capture-ledger
pnpm 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 が「撮れた」と言えば、復旧は終わり。

repo は waggle → capture-ledger と改名したが、Windmill の folder は f/waggle/ のまま。folder のパスは webhook URL の一部 (/api/w/crawler/jobs/run/f/f/waggle/crawl_level)で、変えると capture-ledger 側に設定した webhook が壊れる。名前ではなく外部契約として 据え置いてある。