mcpField
A
adding-personhog-rpc

adding-personhog-rpc

github.com/posthog開発40.5k151 回インストール今日更新
リポジトリ

adding-personhog-rpc について

PersonHog の RPC を追加する PostHog エンジニア向け開発スキルです。データアクセス設計から proto、Rust サービス、Python と Node.js のクライアント更新までを扱い、インデックス、ルーティング、再試行時の安全性を重視します。

主な機能

  1. 01対象テーブルとデータ種別の確認
  2. 02既存インデックスに沿ったクエリ設計
  3. 03サービスとルーティングの proto 定義
  4. 04Python と Node.js クライアントの更新
  5. 05Rust のストレージ層と RPC 実装
  6. 06テスト追加とビルド検証

活用シーン

  1. 01PersonHog が扱うデータ向け RPC の追加
  2. 02RPC 用クライアントラッパーとテスト用実装の更新
  3. 03RPC ルーティング、再試行、DB アクセスの検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/posthog/posthog --skill adding-personhog-rpc

インストール後、Claude Code で/adding-personhog-rpcを入力して読み込まれたか確認します。

同梱ファイルreferences/database-indexes.mdreferences/proto-conventions.md

詳細

personhog RPC の追加

このスキルでは、新しい RPC をエンドツーエンドで追加する手順を説明します。 proto 定義、コード生成、Rust 実装、クライアントの更新です。

始める前に: 適格性チェック

Personhog は、person、distinct ID、group、group type mapping、cohort membership、feature flag hash key override のデータを提供します。 アクセスするデータがこれらのテーブルのいずれかに存在しない場合、この RPC は personhog に属しません:

テーブルデータカテゴリルーティング
posthog_personPersonData読み取り: replica (結果整合) または leader (強整合)。書き込み: leader
posthog_persondistinctidPersonDataperson と同じ
posthog_groupNonPersonDataすべての操作: replica
posthog_grouptypemappingNonPersonDataすべての操作: replica
posthog_cohortpeopleNonPersonDataすべての操作: replica
posthog_featureflaghashkeyoverrideNonPersonDataすべての操作: replica
posthog_personoverridePersonData読み取り/書き込みは person のルーティングに従う
posthog_personlessdistinctidPersonDataperson と同じ

上記にテーブルが記載されていない場合は、停止してください — このデータは personhog を経由すべきではありません。

ステップ 0: データアクセスパターンを設計する

proto を書く前に、必要な SQL クエリを明確にしてください。 次に、利用可能なインデックスに対してそれを検証します — references/database-indexes.md を参照してください。

重要な質問:

  • このクエリはどのテーブルにアクセスしますか?
  • WHERE 句は既存のインデックスに一致しますか? すべてのクエリはインデックススキャンでなければならず、シーケンシャルスキャンであってはなりません。
  • これは読み取りですか、それとも書き込みですか? これがルーティングを決定します (上記の表を参照してください)。
  • 読み取りの場合: 呼び出し元は強整合性 (primary プール) を必要としますか、それとも結果整合性 (replica プール) で許容できますか?
  • バッチ検索の場合: バッチは単一のチーム内ですか、それともチームをまたぎますか?

ステップ 1: proto メッセージと RPC を定義する

すべての proto ファイルは proto/personhog/ にあります。 メッセージの規約と実例については references/proto-conventions.md を参照してください。

何をどこに追加するか
  1. メッセージ型 → proto/personhog/types/v1/<domain>.proto (person.proto、group.proto、cohort.proto、feature_flag.proto、または common.proto)
  2. サービス RPC → proto/personhog/service/v1/service.proto (クライアントが呼び出す公開 API)
  3. レプリカ RPC → proto/personhog/replica/v1/replica.proto (ルーターが委譲する内部 API)
  4. リーダー RPC → proto/personhog/leader/v1/leader.proto (これが leader にルーティングされる person データの書き込みである場合のみ)

サービスとレプリカの proto は、同一のシグネチャで RPC を宣言する必要があります。 ルーターは service → replica (または leader) への委譲を透過的に行います。

リーダー RPC は at-least-once 配信下で安全でなければならない

リーダーパスのリクエストは複数回配信される可能性があります。クライアントは不明瞭な失敗の後に UNAVAILABLE をリトライし、 ルーターは内部的にフェンスおよびトランスポートでバウンスされたリクエストを再送します。 したがって、すべてのリーダー RPC は再配信下で収束するか — 読み取り専用のルックアップ、同じ状態に再適用されるマージ、トゥームストーン方式の削除、max-merge のバージョンフロア — または重複を検出できるように明示的な操作アイデンティティを持つ必要があります。 正確な契約に注意してください。収束するマージであってもインターリーブには敗北します (再送が、その間に別の呼び出し元が行った同一フィールドへの書き込みを上書きする可能性があります)。 この残差は現時点では許容されており、操作アイデンティティによって解消されます(personhog-leader の README を参照)。 収束もせずアイデンティティも持たない RPC(ガードされていないインクリメント、append)を追加してはなりません。 必要な操作がどちらの形にも当てはまらない場合は、proto を定義する前に冪等キーを持つように再設計してください。

Step 2: クライアントスタブを生成する

Python
bin/generate_personhog_proto.sh

次に 3 つのファイルを更新します:

  • posthog/personhog_client/proto/__init__.py — 新しいリクエスト/レスポンスメッセージ型の再エクスポートを追加
  • posthog/personhog_client/client.py — 既存のメソッドのパターンに合わせたラッパーメソッドを追加
  • posthog/personhog_client/fake_client.py — テスト用にそのメソッドを実装
Node.js
cd nodejs && pnpm run generate:personhog-proto

次に更新します:

  • nodejs/src/common/personhog/groups.ts または persons.ts — 対応する操作クラス (PersonHogGroupOperations / PersonHogPersonOperations)に、既存のメソッドのパターンに従って ラッパーメソッドを追加します。client.ts はこれらの操作オブジェクトを構築して公開するだけで、 RPC ラッパー自体は保持しません。
  • nodejs/src/common/personhog/client.test.ts — 新しい RPC 用に SERVICE_DEFAULTS へデフォルトスタブを追加
Rust

生成ステップは不要です — tonic は cargo build で再生成します。 ただし、RPC を実装する必要があります(次のステップ)。そうしないとビルドが失敗します。

Step 3: Rust で実装する

コンパイラーが導いてくれます — proto を定義すれば、cargo build のエラーがどのトレイトメソッドが不足しているかを正確に教えてくれます。

3a. ストレージ層(personhog-replica)
  1. トレイトメソッドを追加 する: rust/personhog-replica/src/storage/traits/<domain>.rs
  2. クエリを実装 する: rust/personhog-replica/src/storage/postgres/<domain>.rs
    • sqlx::query_as! または sqlx::query! マクロを使用
    • DB_QUERY_DURATION および DB_ROWS_RETURNED メトリクスによるタイミング計測を追加
    • 読み取りには self.replica_pool、書き込みには self.primary_pool を使用
    • 空のバッチ入力に対しては早期リターン
  3. ストレージテストを追加 する: rust/personhog-replica/tests/storage_tests.rs
3b. サービス層(personhog-replica)
  1. RPC ハンドラーを追加 する: rust/personhog-replica/src/service/mod.rs
    • proto リクエストからフィールドを抽出
    • ストレージトレイトメソッドを呼び出す
    • ストレージの結果を proto レスポンスに変換
    • ストレージのエラーを tonic の Status コードにマッピング
  2. サービステストを追加 する: rust/personhog-replica/tests/service_tests.rs
3c. ルーターの配線(personhog-router)

ルーターはリクエストバイトをデコードせずに転送するため、新しい RPC にハンドラーは不要です。

  1. メソッド名を追加 する: rust/personhog-router/src/proxy.rs の KNOWN_METHODS に、リストをソートした状態で追加
    • リーダーに到達する必要があるメソッドは proxy.rs で名前によってマッチングされます。それ以外はすべてレプリカに転送されます
    • 同じファイル内の known_methods_is_sorted と known_methods_matches_service_proto は、リストが service.proto と一致するまで失敗します
  2. メソッドを追加 する: 生成されたトレイトを実装するすべての PersonHogService モックに追加します。personhog 外のものも含みます(rust/personhog-router/tests/common/mod.rs、rust/property-defs-rs/tests/)。tonic のトレイトにはデフォルトメソッドがありません

同じ振る舞いの複数のバリエーションをテストする場合は、rstest のパラメーター化テストを使用してください。

Step 4: 検証

cargo build -p personhog-proto
cargo build -p personhog-replica
cargo build -p personhog-router
cargo test -p personhog-replica
cargo test -p personhog-router

チェックリスト

  • クエリが既存のインデックスを使用している(シーケンシャルスキャンなし)
  • Proto メッセージが types/v1/<domain>.proto に追加されている
  • RPC が service.proto と replica.proto の両方に追加されている(必要に応じて leader.proto にも)
  • リーダー RPC のみ: 操作が at-least-once 配信下で安全である(再配信に対して収束する — 読み取り専用、再適用可能なマージ、tombstone、max-merge — または明示的な操作アイデンティティを持つ)
  • Python スタブが生成され、proto/__init__.py が更新され、client.py のメソッドが追加され、fake_client.py が更新されている
  • Node.js スタブが生成され、client.test.ts の SERVICE_DEFAULTS が更新されている
  • Rust のストレージトレイト + postgres 実装 + サービスハンドラー + ルーター配線が実装されている
  • ストレージ、サービス、ルーターの各レイヤーにテストが追加されている
  • 3 つのクレートすべてで cargo build と cargo test が成功する

コメント