📐 仕様解説 — システム構成と再発防止

2026-07-08 の「リモートホストIP制限」インシデントを受けた v2 アーキテクチャの全面解説。
← サイトトップへ戻る

0 件/日
ローカルPC → 西松屋本体サイト
へのアクセス(v2で経路自体を廃止)
〜60 件/日
Cloudflare → 検索API(別基盤)のみ
1日1回・150ms間隔・15秒タイムアウト
本日の自動更新(8:00 JST)
下の「ライブ証跡」参照

1. 何が起きたか(インシデント)

旧構成(v1)は自宅/事務所のPCとその回線から毎朝、西松屋オンラインストア本体 (www.24028-net.jp)の在庫確認ページを 131品番 × 最大3回再試行 × 並列6接続で 取得していました。西松屋のECプラットフォーム(ebisumart系)のWAFがこれをbotと判定し、 回線のグローバルIP単位で制限(403「リモートホストIPが制限されています」)を発動。 ブラウザでの通常閲覧まで同じエラーになりました。

2. 構成の変更点(Before / After)

v1 旧構成 PC依存・本体サイト直撃

〜2026-07-11。制限の原因となった構成

🖥 自宅/事務所の Windows PCタスクスケジューラ 毎朝7:00(PCの電源が必要)
↓ Node.js 実行
scrape.mjs + verify_stock.mjs ほか在庫検証: 131品番 × 並列6 × 再試行3
↓ 自宅回線のIPから 数百リクエスト/日 ⚠️
西松屋本体 www.24028-net.jpebisumart WAF → ✗ 2026-07-08 IP制限発動
→ ブラウザ閲覧まで巻き添えで403
↓ 生成した JSON を wrangler で手動アップロード
Cloudflare Pages(静的配信のみ)PCが止まると更新も止まる

v2 現行構成 Cloudflare内で完結

2026-07-11〜。ローカルPCと本体サイトを経路から排除

⏰ Durable Object Alarm(CoordeScheduler)毎朝 23:00 UTC = 8:00 JST に自動発火。PC不要
↓ Worker がパイプライン実行(未完なら90秒後に自動継続)
⚙️ Worker: kyoudai-coorde-cronfetch予算40/回でハードストップ・各fetch15秒タイムアウト
↓ 検索API のみ 〜60リクエスト/日・150ms間隔 ✓ 本体サイトへは0件
検索API nishimatsuya-f-s.snva.jp(NaviPlus)西松屋本体とは別ホスト・別基盤。IP制限発動中も200を返し続けた実績
↓ 生成JSONを保存(失敗日は前日分を温存 = last-good)
🗄 Workers KV(COORDE_KV)data / cheap / uniqlo / corners / feed / status
↓ /api/* で配信(KVに無ければ静的フォールバック)
📄 Cloudflare Pages + Pages Functionsサイト本体・画像プロキシ(許可ホストのみ)・RSS
↓ 閲覧
👪 閲覧者のブラウザ商品画像・商品リンクはブラウザが直接西松屋を閲覧(通常のWeb閲覧と同一で制限対象外)

3. Cloudflareサービス / ソフトウェアスタック対比

レイヤv1(旧)v2(現行)
スケジューラWindows タスクスケジューラ(PC電源依存)Durable Object Alarm(SQLiteバックエンド。cronトリガー枠を消費せず、単一スレッド実行で二重起動が構造的に不可能)
データ取得ローカルNode.js。本体サイト在庫ページを131品番×並列6でスクレイプWorker上の共有パイプライン src/pipeline.mjs検索APIのみ(json_grouping)。色×サイズ実在庫は仕様上取得不能になったためデザイン単位表示に変更
データ保存ローカルファイル → 毎朝 wrangler で全量再デプロイWorkers KV。ステップ成功時のみ上書き(last-good保持)
配信Cloudflare Pages(静的のみ)Pages + Pages Functions(/api/* をKVから配信、画像プロキシ、RSS)+ Cache API
フロント単一リスト(Tシャツのみ)3タブ(お揃いTシャツ / ¥1,000以下パンツ・レギンス / 他ブランド)+ SEO(JSON-LD/OGP/sitemap) + アフィリエイト基盤
監視deploy.log(ローカル。誰も見ず4日間障害に気づけなかった)公開 /api/status.json(毎tick更新・ステップ別成否とfetch数)
コード管理なし(ローカルのみ)GitHub公開リポジトリ(シークレット非含有)

4. なぜ再発しないか — 5つの根拠

原因経路そのものを廃止

制限の原因は「ローカル回線 → 本体サイトへの大量アクセス」。v2のコードには www.24028-net.jp へサーバー側からfetchする処理が1行も存在しません(GitHubで全コード検証可能)。旧タスクスケジューラも無効化済み。原因行為が物理的に発生し得ません。

アクセス先は別基盤の検索API

v2が使う nishimatsuya-f-s.snva.jp は検索SaaS(NaviPlus)で、制限を発動したebisumart WAF(本体サイト)とは別ホスト・別基盤。実際、IP制限の発動中もこのAPIは一貫して200を返し続けています(ローカルからもCloudflareからも確認済み)。

リクエスト量を桁で削減+上限を機械的に強制

v1: 数百リクエスト/日・並列6。→ v2: 1日1回・合計約60リクエスト・直列・150ms間隔。さらに1実行あたりfetch予算40でハードストップ、各fetch15秒タイムアウト。暴走してもWorkersの実行時間・サブリクエスト上限が二重の天井になります。

自宅回線とCloudflareの分離

更新はCloudflareのデータセンターから実行され、自宅/事務所の回線IPはもう更新処理に一切使われません。この回線からは今後「普通に閲覧するだけ」なので、制限を再発・延長させる要因がありません(現在の制限も待てば解除される見込み)。

万一に備えた縮退設計(last-good)

仮に将来どこかがブロック・障害になっても、失敗したステップは前日データを配信し続け、他ステップは独立して更新されます。サイトが止まったり空になったりはしません。実例: H&MはCloudflareからブロックされるため自動スキップで運用中。

毎日の公開証跡

実行結果は毎朝 /api/status.json に公開され、誰でも「今日も制限されずに完走したこと」を確認できます(下のライブ証跡がその実データです)。

5. ライブ証跡 — 本日の自動更新(このページが毎日更新される証明)

以下は静的な文章ではなく、いまこの瞬間に /api/status.json と各データの生成時刻を読み込んで表示しています。 日付と全ステップ✓が毎日進んでいくこと自体が「Cloudflare側の処理が制限を受けていない」ことの継続的な実証になります。 (※将来にわたる外部サイト仕様の不変までは誰にも保証できないため、本サイトは「証明」を静的な断言ではなく毎日検証可能な公開データで提供する方針です)

最新実行ステータス

読み込み中…

参考: 移行直後の初回実行ログ(2026-07-11 23:07 JST・手動検証)

ステップ結果外部fetch数内容
tshirt✓ 成功9お揃いTシャツ 54デザイン生成
cheap✓ 成功7¥1,000以下 378件(パンツ286・レギンス92)
uniqlo✓ 成功37セール品自動選定(¥790)
corners✓ 成功6ZARA(6)・ヒラキ(6)。H&Mは自動スキップ(設計どおり)
feed✓ 成功0RSSフィード生成
合計59v1の在庫検証だけで最低131×1〜3回だったものを1/10以下に削減

6. 障害時の縮退挙動(フェイルセーフ一覧)

事象挙動サイトへの影響
検索APIが一時エラー3回再試行 → 2tick失敗で当該ステップをスキップ前日データを配信継続(last-good)
fetch予算(40/回)を使い切る失敗扱いにせず90秒後の次tickで同ステップから再開更新が数分遅れるだけ
他ブランドサイトのブロック/構造変更そのブランドのみ自動スキップ(実例: H&M・GAP)該当コーナーが非表示になるだけ
生成結果が0件(上流異常)安全弁が発動しKVを上書きしない前日データを配信継続
想定外エラーでAlarm処理が失敗10分後に再Alarmを自動設定(チェーンを絶やさない)自動リカバリ

7. 確認用リンク