mcpField
D
django-startup-time

django-startup-time

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

django-startup-time について

PostHog のバックエンド開発者向けスキルです。Django の起動時のインポートコストを管理し、遅延インポートによる回帰を防ぐためのガード、測定方法、注意点をまとめています。

主な機能

  1. 01Django 起動時のインポート予算
  2. 02重い依存関係の遅延インポート
  3. 03モデルとレシーバーの登録指針
  4. 04起動性能の測定方法
  5. 05回帰を防ぐチェックリスト

活用シーン

  1. 01バックエンドアプリやレシーバーの追加
  2. 02インポート予算違反の調査
  3. 03遅延インポートの影響評価

インストール

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

$npx skills add https://github.com/posthog/posthog --skill django-startup-time

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

詳細

Django の起動時間

詳細な背景 — 4 つの仕組み(遅延ルーター、モデル登録、レシーバーの配線、起動時の GC ウィンドウ)、リグレッションガード、それらを壊さずにコードを追加する方法、測定方法、および詳細なトラップの解説: docs/internal/django-startup-time.md。詳細の唯一の情報源はそのドキュメントです。このスキルはトリガーとチェックリストです。

ガードは posthog/test/repo_invariants/test_startup_import_budget.py にあります。失敗した場合は、インポートを遅延させてください — 回避するためにエントリを削除しないでください。 逆に、セットアップ時に重大な重量級ライブラリを意図的に遅延させた場合は、FORBIDDEN_AT_SETUP に追加してください(素の django.setup() にそれが含まれていないことを確認したうえで)。プロダクトのファサードやそのコントラクトモジュールをそこに固定しないでください。ファサードはどこからでもインポート可能である必要があるため、代わりに遅延させた重量級モジュールを固定してください。まだ誰も名前を付けていない新しいインポートは test_no_new_heavy_imports_at_setup で捕捉されます。posthog/test/repo_invariants/setup_import_baseline.txt に含まれていないパッケージで、セットアップ時に 100ms 以上かかるものはビルドを失敗させます — それを遅延させてください。ベースライン化するのは、すべてのプロセスがセットアップ時に本当に必要とするものだけにしてください。

バックエンドコードを追加する際のデフォルト

  • 新しいアプリ/プロダクト: models/__init__.py からモデルを登録し、AppConfig.ready() からレシーバーを配線し、ready() は軽量に保ちます。
  • 新しいレシーバー: 所有する AppConfig.ready() で、専用の軽量モジュール(activity_logging.py、signals.py)から配線してください — たとえ今日は軽量に見えても、API/viewset モジュールを経由しないでください。それらは重量級のインポートを蓄積し、ready() が気付かないうちにそれらを継承してしまいます。
  • 新しい重量級の依存関係(ベンダー SDK、Temporal/AI/ClickHouse、pandas/pyarrow/scipy): それを使用するパス上で # noqa: PLC0415 を付けて関数ローカルにインポートし、モジュールスコープでは絶対にインポートしないでください。
  • セットアップパス上のモジュールでのスキーマ型: enum は posthog.schema_enums から(低コスト)。pydantic モデルはそれらを使用するメソッド内でのみ posthog.schema から。セットアップパス上でモジュールレベルの from posthog.tasks... はなし — CeleryQueue は posthog.celery_queues にあります。
  • 新しい viewset/ルート: それはもはやセットアップ時にロードされません — インポートの副作用に依存しないでください。ルートは rest_router.py に置き、__init__.py のシムには置かないでください。
  • どこで削るか: セットアップパスのエントリ(ready() が配線するモジュール、モデルファイル、apps.py)で行い、プロダクトのファサードを消費するモジュールの内部では絶対に行わないでください。ファサードがセットアップに到達する場合、そのエントリはそこに至る実装モジュールを遅延させます。ファサードのインポートはモジュールスコープに留めます。セットアップパスが重量級モジュールから 1 つのシンボルを必要とする場合は、それを軽量モジュールに移動して再エクスポートしてください。
  • あらゆる遅延はコストを移転します — 今どのプロセスが、どのパスで支払うのか、そしてそのパスがレイテンシーに敏感かどうかを問いかけてください(バックグラウンドワーカーが遅延して支払う: 問題なし。Web ワーカーが最初のリクエストで支払う: 通常は問題あり)。

コミット前に確認すべき罠

それぞれ 1 行です。詳細な解説と各項目の修正手順はドキュメントに記載されています。

  • ready() が重い依存関係を起動時に再び引きずり込む — レシーバーのモジュールをインポートすると、そのモジュールレベルのインポートも実行されます。配線後に再測定してください。
  • レシーバーのサイレントな消失 — 消失したレシーバーはエラーになりません。ルーターを構築しないプロセス(manage.py shell、celery、migrate)で再現してください。
  • モデルがレジストリから消える — viewset のインポート経由でしか到達できないモデルは makemigrations/admin/mypy を壊します。models/__init__.py からインポートし、その後 dmypy stop を実行してください。
  • レイジールーターのマージコンフリクト — __init__.py のシムを維持し、master のアグリゲーターの差分を rest_router.py に移植してください。
  • アグリゲーターパッケージの __init__ — PEP 562 の __getattr__ でシムし、importlib.import_module と __all__ ホワイトリストを使用してください(包括的なキャッチオールは兄弟インポートで再帰したりデッドロックしたりします)。
  • シリアライザーのフィールド kwargs はインポート時に実行される — choices=... の入力は関数ローカルに遅延できません。定数をインポートの軽いモジュールに移動してください。
  • 消えた再エクスポート — モジュールを再生成/シムすると、他のコードがそこから偶発的にインポートしていた名前(例: schema.BaseModel)が失われます。相対インポートの表記も含め、古い名前空間の利用者を grep で探してください。
  • パッチターゲットは呼び出し時のインポートで壊れる — mod が呼び出し時に helper をインポートすると、@patch("mod.helper") はインターセプトしなくなります。代わりに定義元のモジュールにパッチを当ててください。
  • 不正なマージでのスナップショット再生成 — マージ後のブランチに対して .ambr を再生成し、それがリグレッションを覆い隠していないことを確認してください。
  • 作業ではなくラッパーを測定する — プロセス内で計測してください。pyinstrument ではなく importtime + tuna、循環と入口の列挙には grimp を使用してください。
  • どこを遅延すべきか当てずっぽうにする — importtime のログに対して hothog を実行してください。その 1-cut@ 列が遅延すべき支配元を示し、--compare が前後の比較を提供します。このスキルと hothog を PR のエージェントコンテキストに記載し、レビュアーがカットの選び方を把握できるようにしてください。
  • GC による importtime の幻のコスト — gc.disable() で再キャプチャしてください。コストが消えれば、その所見はモジュールではなく GC です。エントリーポイントの GC ウィンドウのクローズは finally に保ってください。

コメント