✓=レビュー済 ○=未レビュー ⚠=Suspect(複数同時表示あり。IDクリックで詳細へ)
| グループ | REQ | ARCH | SPEC | TST | IMPL | ADR |
|---|---|---|---|---|---|---|
| HOOK | REQ009 ✓ 関数の実行前、キャッシュヒット時、キャッシュミス時にカスタムコールバック(フック)を実行できること。スレッドセーフなフック実装を提供すること。 | ARCH009 ✓ ## コンポーネント構成 ```mermaid graph TD A[core.Spot] -->|イベント通知| B[HookBase] C[Thr... | SPEC019 ✓ ## インターフェース ```python class HookBase: def pre_execute(self, ctx: PreExecute... | TST019 ✓ ## 目的 Hook システムはキャッシュライフサイクルへのユーザー拡張ポイント(ロギング、メトリクス収集、監査等)であり、フック内の不具合がメインの関数実行... | IMPL019 ✓ ## 実装概要 タスク実行ライフサイクルに介入するインターフェース `HookBase` と、 そのスレッドセーフ版 `ThreadSafeHookBase`... | ADR035 ✓ # クラスベース・フックシステムと並列実行サポート ## Context and Problem Statement / コンテキスト `beautyspo... |
| リンク方向 | カバー数 | カバー率 | 未カバー |
|---|---|---|---|
| ARCH → REQ | 1 / 1 | 100.0% | — |
| SPEC → ARCH | 1 / 1 | 100.0% | — |
| TST → SPEC | 1 / 1 | 100.0% | — |
| IMPL → SPEC | 1 / 1 | 100.0% | — |
| ADR → REQ | 1 / 1 | 100.0% | — |
関数の実行前、キャッシュヒット時、キャッシュミス時にカスタムコールバック(フック)を実行できること。スレッドセーフなフック実装を提供すること。
親: —
graph TD
A[core.Spot] -->|イベント通知| B[HookBase]
C[ThreadSafeHookBase] --> B
B -->|コンテキスト| D[Context Objects]
E[PreExecuteContext] --> D
F[CacheHitContext] --> D
G[CacheMissContext] --> D
| コンポーネント | 責務 | インターフェース |
|---|---|---|
| HookBase | 実行ライフサイクルの各段階で呼び出される抽象基底クラス | pre_execute, on_cache_hit, on_cache_miss |
| ThreadSafeHookBase | RLockを用いて各フックメソッドの実行を直列化する | __init_subclass__ による自動ラップ |
| Context Objects | フックに渡される実行時の引数、結果、例外、メタデータのコンテナ | ctx.args, ctx.result 等 |
sequenceDiagram
participant Spot as core.Spot
participant Hook as HookBase
participant Fn as Target Function
Spot->>Hook: pre_execute(ctx)
alt キャッシュヒット
Spot->>Hook: on_cache_hit(ctx)
else キャッシュミス
Spot->>Fn: execute()
Fn-->>Spot: result
Spot->>Hook: on_cache_miss(ctx)
end
| 技術領域 | 選定 | 理由 |
|---|---|---|
| パターン | オブザーバー | コアロジックを汚さずに、ログ出力や統計取得等の横断的関心を分離 |
| スレッド安全 | 自動装飾 (Decorator) | ユーザーが意識せずに、サブクラス化するだけで安全なフックを実装可能 |
| 実行制御 | 準同期実行 | フック内の例外をキャッチしログ出力に留めることで、主処理を保護 |
透過性: フックの実行失敗(例外)は主処理の結果に影響を与えない
柔軟性: 関数ごとに異なるフックリストを hooks=[...] で指定可能
パフォーマンス: フック未登録時のオーバーヘッドを最小化するガード条件を実装
親: REQ009
子: SPEC019
class HookBase:
def pre_execute(self, ctx: PreExecuteContext) -> None: ...
def on_cache_hit(self, ctx: CacheHitContext) -> None: ...
def on_cache_miss(self, ctx: CacheMissContext) -> None: ...
ThreadSafeHookBase を継承した場合、メタクラスが自動的に各メソッドを with self._lock: で包む| コンテキスト | 保持データ |
|---|---|
PreExecuteContext |
func, args, kwargs, cache_key |
CacheHitContext |
cache_key, result, metadata |
CacheMissContext |
cache_key, result, execution_time |
hooks=[h1, h2] と指定した場合、h1 -> h2 の順で実行される。親: ARCH009
Hook システムはキャッシュライフサイクルへのユーザー拡張ポイント(ロギング、メトリクス収集、監査等)であり、フック内の不具合がメインの関数実行に影響を与えないことが最重要の契約である。また ThreadSafeHookBase の自動ロック機構の正確性を保証する。
pre_execute → 関数実行 → on_cache_miss の順でフックが呼ばれること。キャッシュヒット時に pre_execute → on_cache_hit の順で呼ばれることPreExecuteContext, CacheHitContext, CacheMissContext)が正しい情報(func_name, args, result 等)を含むこと__init_subclass__ によりユーザー定義メソッドが自動的に RLock でラップされ、複数スレッドからの同時呼び出しで競合状態が発生しないことreferences: tests/integration/core/test_hooks.py
親: SPEC019
子: —
タスク実行ライフサイクルに介入するインターフェース HookBase と、
そのスレッドセーフ版 ThreadSafeHookBase の実装。
pre_execute, on_cache_hit, on_cache_miss の各コールバックが提供される。
ThreadSafeHookBase は __init_subclass__ を利用し、サブクラスで定義された
フックメソッドを自動的にロックでラップする。
ユーザーが手動でロックを書く手間を省くため、メタクラス的なアプローチを採用。
クラス定義時にフックメソッドを抽出し、_wrap_with_lock デコレータで包むことで、
ユーザーコードを汚さずに完全な排他制御を実現している。
当初の Lock から RLock に変更された。
サブクラスが super().pre_execute(...) のように親のメソッドを呼び出した際、
同一スレッドが再度ロックを取得しようとしてデッドロックする問題を防ぐため。
_wrap_with_lock は functools.wraps を使い、元のメタデータを保持するThreadSafeHookBase は __getattr__ をオーバーライドし、
super().__init__() の呼び出し忘れに対して親切なエラーメッセージを返すreferences: src/beautyspot/hooks.py
親: SPEC019
子: —
beautyspot のコアロジックを汚染することなく、ユーザーが「トークン計算」や「レイテンシ計測」などのカスタムメトリクスを収集できる仕組みが必要です。また、並列実行環境においても、競合状態を避けつつ安全に状態を共有・更新できることが求められます。
HookBase) と、フェーズ別に分離された専用コンテキストオブジェクトの導入。Chosen option: Option 2.
HookBase)状態(開始時間や累計カウンタ)を保持しやすいよう、クラスベースのインターフェースを採用します。
ThreadSafeHookBase)サブクラスでオーバーライドされたメソッドを自動でロックラッパーで包む仕組みを導入します。これにより、ユーザーは明示的なロック制御なしでスレッドセーフな集計が可能になります。
実行フェーズごとに最適化された 3つの専用コンテキストクラス を提供します。
* PreExecuteContext: 関数実行前。
* CacheHitContext: キャッシュ取得成功時。
* CacheMissContext: 関数実行完了時。
フックが登録されていない場合は、コンテキストオブジェクトの生成を完全にスキップします。
親: REQ009
子: —