ここまでは、こちらから取りに行く方式を扱ってきました。定期的に問い合わせて、変わっていれば取る。単純で分かりやすい形ですが、2つの無駄があります。変わっていないときも問い合わせることと、変わってから気づくまで時間がかかることです。
は、この向きを逆にします。相手側で変化が起きたときに、向こうから通知が飛んでくる。無駄な問い合わせが消え、反映も速くなります。
ただし、受け取る側には新しい責任が生まれます。常に受け取れる状態を保つことと、同じ通知が2回来ても壊れないことです。取りに行く方式では考えなくてよかった問題が出てきます。
同じ通知が2回来る
通知の送り主は、届いたかどうかを応答で判断します。こちらが処理に成功していても、応答を返す前に接続が切れれば、相手には失敗に見えます。すると同じ通知がもう一度送られてきます。
だから受け取る側にはが要ります。同じ通知を2回処理しても、結果が変わらないようにする。通知には一意の識別子が付いていることが多いので、処理済みの識別子を覚えておくのが基本形です。
import sqlite3from pathlib import Path
DB = Path("data/webhook_seen.sqlite")
def init(db_path: Path = DB) -> None: db_path.parent.mkdir(parents=True, exist_ok=True) with sqlite3.connect(db_path) as con: con.execute("CREATE TABLE IF NOT EXISTS seen (event_id TEXT PRIMARY KEY)")
def mark_if_new(event_id: str, db_path: Path = DB) -> bool: """初めて見る通知なら True。すでに処理済みなら False。
主キーの制約で二重登録を防ぐので、確認と登録の間に 別の処理が割り込んでも二重に処理されない。 """ with sqlite3.connect(db_path) as con: try: con.execute("INSERT INTO seen (event_id) VALUES (?)", (event_id,)) except sqlite3.IntegrityError: return False return True通知の本文には、変化した内容がすべて入っているとは限りません。「この識別子のものが更新された」とだけ書かれていて、中身は改めてで取りに行く形が一般的です。通知は合図であって、データそのものではないと考えておくほうが安全です。
受け取った通知は、処理する前にへそのまま保存してください。後から「本当にその通知が来ていたのか」を確かめられます。送り主と食い違ったときに、証拠が無いと話が進みません。
受け取り口は誰でも叩ける
通知を受け取る口は、インターネットから見える場所に置くことになります。つまり送り主以外も叩けます。偽の通知を送られると、存在しないデータを処理してしまいます。
で 200 を返しさえすれば受理されるので、検証を省いても動いてしまいます。多くのサービスは、通知に署名を付けています。共有の秘密を使って本文から署名を計算し、送られてきた署名と一致するかを確かめることで、本物かどうかを判定できます。この検証を省略してはいけません。
import hashlibimport hmac
def verify_signature(body: bytes, signature: str, secret: str) -> bool: """本文から署名を計算し、送られてきたものと一致するか確かめる。
== で比べると、一致しない位置によって処理時間が変わり、 それを手がかりに署名を推測されうる。専用の関数を使う。 """ expected = hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature)通知の送り主は、応答が遅いと失敗とみなして再送します。受け取った本文をそのまま保存して、すぐに成功を返す。中身の処理は後回しにする。この形にしておかないと、処理が重い日に再送が積み重なります。
取りこぼしに気づけない
通知方式の弱点は、来なかったことに気づけないことです。取りに行く方式なら、取れなければ失敗として分かります。通知は、送られてこなければ何も起きないだけです。相手側の障害でも、こちらの受け取り口が落ちていても、静かに欠けます。
だから通知方式を採るときも、定期的に取りに行く仕組みを併用するのが安全です。1日1回、全体を突き合わせて欠けがないかを確認する。通知で速さを取り、定期取得で確実さを担保する、という組み合わせになります。
受け取り口を用意して運用し続けるのは、それなりの負担です。更新の速さが本当に必要かを先に考えてください。1日1回で足りるなら、取りに行く方式のほうが簡単で壊れにくい。次回は、その定期実行の組み方を扱います。
通知方式は、速さと引き換えに運用の手間が増えます。取りに行く方式で足りるなら、無理に切り替える必要はありません。
受け取り口を公開したままにしておくと、使わなくなった後も外から叩かれ続けます。役目を終えたら閉じる。これは取得の棚卸しとして、後の回でまとめて扱います。
取りに行く方式と受け取る方式は、どちらが優れているという話ではありません。更新の速さがどれだけ必要かで決まります。速さが要らない場面で通知方式を選ぶと、運用の手間だけが増えます。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。