· HARUBOUYA · dataflow · 14 min read

お天気APIをECサイトに出すまでのデータフロー

天気に合わせた接客を出したいです。ブラウザから直接APIを叩くとリクエスト数が読めず費用も跳ねます。日次でまとめて取得し、CSVに整形して置く構成と、決めておくべき仕様を書きます。

雨の日に傘をさして立つ人のイラスト

「雨の日に、雨向けの商品をおすすめしたい」という要望はよく出ます。やること自体は単純で、天気を取ってきて、それに合わせて表示を変えるだけです。

ただしどこで天気を取るかを間違えると、費用と安定性の両方で困ります。ここでは実際に組んだ構成と、決めておくべき仕様を書きます。

問題:ブラウザから直接APIを叩く構成

最初に思いつくのは、サイトを開いた人のブラウザから気象APIを呼ぶ方式です。位置情報を取り、その場で天気を問い合わせ、結果に応じて表示を変えます。

動きはしますが、次の問題があります。

問題内容
リクエスト数が読めませんアクセス数に比例して増えます。キャンペーンで急増すると一気に跳ねます
上限超過気象APIには契約上のリクエスト上限があります。超えると止まります
費用が読めません従量課金のため、月末まで金額が確定しません
APIキーが見えますブラウザから呼ぶ以上、キーは画面の裏側に置くことになります

最後の点は特に大きいです。ブラウザの開発者ツールで F12 キー → Network タブ を開けば、送信されているリクエストのヘッダーが誰でも見られます。そこにAPIキーが載っていれば、そのまま第三者に使われます。

仕組み:サーバー側で1日1回取る

解決は単純で、取得する場所をブラウザからサーバーに移します。

区分構成
変更前訪問者のブラウザが、そのつど気象APIを呼びます
変更後サーバーが1日1回まとめて取得し、クラウドストレージに置きます。接客ツールはその置いたファイルを読みます

これでリクエスト数が固定されます。

項目値
対象地点約140地点(気象庁の一次細分区域に相当する単位)
取得する種類日別予報・時間別予報の2種
実行頻度1日1回
月間リクエスト数140 × 2 × 31 ≒ 約8,700件

アクセス数がどれだけ増えても、この数は変わりません。費用が事前に確定することが、この構成の最大の利点です。

全体の流れ

Cloud Scheduler(毎日2:30に起動)
  ↓
Cloud Workflows(全体の順番を管理)
  ↓
Cloud Run ①:気象APIを呼び、取得結果を中間バケットへ
  ↓
Cloud Run ②:中間バケットのファイルをCSVに変換し、公開用バケットへ配置
  ↓
接客ツール:CSVを日次で取り込み → 天気セグメントを作る → 接客を出す

各段の役割は次の通りです。

順サービス役割
1Cloud Scheduler時刻を決めて起動する。設定はcron形式(例 30 2 * * *)
2Cloud Workflows「①が成功したら②」という順番と、失敗時の扱いを定義します
3Cloud Run ①気象APIを呼ぶ処理。APIキーはこのコンテナの中だけに持ちます
4Cloud Run ②取得データを接客ツールが読める形のCSVに変換し、所定のパスへ置きます
5接客ツール置かれたCSVを取り込み、条件に合う人へ表示を出します

全体の実行時間は5分程度です。接客の開始時刻から逆算して起動時刻を決めます。朝3時に最新データが揃っている必要があるなら、2時半に起動して余裕を持たせます。

Cloud Run を2つに分ける理由

1つにまとめても動きます。分けている理由は、失敗したときにどちらで失敗したかが分かるためです。

気象API側の障害で取得できなかったのか、変換処理のバグで壊れたのかは、原因も対処もまったく違います。分けておけば、ログを見るまでもなく切り分けられます。

決めておくこと

1. 地点の粒度と識別子

天気は地点ごとに違います。何地点を持つかで、データ量も接客の精度も変わります。

粒度地点数の目安向き不向き
都道府県47粗いです。南北に長い県では実態と合いません
一次細分区域約140実用的。天気予報で使われる単位と一致します
市区町村約1,700細かいですが、リクエスト数と保守が跳ね上がります

識別子は地名ではなくコードを使います。地名は表記ゆれが起きるうえ、同じ名前の市町村が存在します。地域メッシュコードのような、数値で一意に決まるものを Key にします。

2. CSVの仕様

接客ツール側が読む仕様に合わせます。実際に使っている形は次の通りです。

カラム内容
メッシュコード地点の識別子。これをKeyにします
地名表示用。市区町村役場の名称を使います
都道府県名絞り込み用
1時間ごとの予報JSONを文字列にしたもの
1日ごとの予報JSONを文字列にしたもの
更新日時バッチを実行した時刻

作成ルールも先に決めておきます。

  • 文字コードは UTF-8
  • ヘッダ行あり
  • JSONを入れた列だけ、全体を " で括ります。JSON内部の " は "" と二重にしてエスケープします
  • JSON部分に改行を入れません。1レコードは必ず1行に収めます
  • 更新日時は、予報の基準時刻ではなくバッチを実行した時刻を入れます

最後の2点が、実際にハマる場所です。JSONに改行が混ざると、CSVとしては別レコードに見えるため取り込みが崩れます。更新日時に予報の基準時刻を入れてしまうと、「データが今日更新されたか」が判定できなくなります。

3. 時刻の扱い

日時はUTCで持つか、日本時間で持つかを最初に決めて、全体で統一します。

起動時刻は日本時間、ファイル名の日付は日本時間、更新日時はUTC、という状態になりやすいです。どれが正解ということはありませんが、混在していると「昨日のファイルが置かれている」ように見える障害の切り分けができなくなります。

4. 置き場所とファイル名

gs://<バケット名>/weather/weather_YYYYMMDD.csv

日付をファイル名に入れます。上書きにしないことで、過去分が残り、障害時にどのデータで接客していたかを追えます。

失敗例

実際に起きたものを含めて挙げます。

失敗何が起きるか対処
1地点だけデータが欠落特定地域の人に接客が出ません。誰も気づきません出力前にレコード件数を検査します。想定と違えば処理を止めます
識別子が重複していました別の市のデータで上書きされますマスタ側で一意性を検査してから使います
APIキーをフロントに書きます開発者ツールから見えますキーはサーバー側の処理の中だけに持ちます。シークレット管理機能を使います
日時の単位が混在「今日のデータがない」に見える障害が切り分けできません保持する形式を1つに決め、変換は表示の直前だけで行います
配置が接客開始に間に合いません前日のデータで接客が出ます開始時刻から逆算し、実行時間の3倍以上の余裕を取ります
リトライを入れていませんAPIの一時的なエラーで、その日1日データがありません取得処理にリトライを設定します。失敗したらログを出して止めます

件数の検査だけは必ず入れます。天気データは見た目が正常でも中身が欠けていることがあり、接客が出ないことに誰も気づかないまま数日過ぎます。

やること

起動時刻を設定する

  1. Google Cloud コンソールで「Cloud Scheduler」を開きます
  2. 「ジョブを作成」を押します
  3. 「頻度」に cron 形式で入力する(毎日2時30分なら 30 2 * * *)
  4. 「タイムゾーン」で「日本標準時(JST)」を選びます
  5. 起動先として Workflows を指定します

タイムゾーンの指定を忘れるとUTCで動きます。日本時間より9時間ずれるため、設定直後に一度手動で実行して、動いた時刻を確認します。

動いたかを確認する

  1. Cloud Workflows の画面で対象のワークフローを開きます
  2. 「実行」タブを見ます
  3. 直近の実行が「成功」になっているかを確認します

失敗している場合は、その行を開くとどのステップで止まったかが表示されます。

出力されたファイルを確認する

  1. Cloud Storage の画面で対象のバケットを開きます
  2. 当日の日付のファイルがあるかを見ます
  3. ファイルサイズが前日と大きく違わないかを見ます

サイズが極端に小さければ、取得が途中で失敗しています。

まとめ

  • 天気を取る場所をブラウザからサーバーへ移すだけで、リクエスト数と費用が固定されます
  • 1日1回、全地点をまとめて取得し、CSVにしてストレージへ置きます。接客ツールはそれを読むだけ
  • 地点の識別子は地名ではなくコードを使います。表記ゆれと重複を避けるため
  • 日時の形式は最初に1つへ統一します。混在が障害切り分けを一番難しくします
  • 出力前の件数検査を必ず入れます。欠落は見た目では分かりません
  • 起動時刻は接客の開始時刻から逆算し、実行時間の3倍以上の余裕を取ります

天気に限らず、外部APIを使った接客はこの形に落ち着きます。取りに行く回数を自分でコントロールできる場所に置く、というだけの話です。

Share:

参考になったら、いいねを押してください。

コメント

    お名前とコメントは、確認後にこのページで公開されます。メールアドレスや電話番号などは書かないでください。

    Back to Blog

    Related Posts

    View All Posts »
    GCPのパイプラインが失敗したらSlackに通知する

    GCPのパイプラインが失敗したらSlackに通知する

    夜間バッチが落ちても誰も気づきません。翌朝データがないと言われて初めて知ります。通知の出口を1本にまとめて、失敗したときだけSlackに流す構成を書きます。