ARCH Specification

Generated at 2026-03-09 22:49:07

1.0 序文 ARCH014

本ドキュメントは、『beautyspot』のアーキテクチャ設計を定義する。

2.0 構成要素 ARCH015

システムを構成する主要コンポーネントとその責務、およびコンポーネント間の相互作用を定義する。

2.1 関数キャッシュアーキテクチャ ARCH001
CACHE

コンポーネント構成

graph TD
  A[bs.Spot Factory] -->|DI/Composition| B[core.Spot]
  B --> C[TaskDBBase]
  B --> D[SerializerProtocol]
  B --> E[BlobStorageBase]
  B --> F[StoragePolicyProtocol]
  B --> G[LimiterProtocol]
  B --> H[LifecyclePolicy]

コンポーネント責務

コンポーネント 責務 インターフェース
core.Spot キャッシュエンジン。キー生成→検索→実行→保存の制御 mark(), cached_run()
TaskDBBase メタデータ永続化。キャッシュキーによる検索と保存 find_by_key(), insert()
SerializerProtocol データのシリアライズ/デシリアライズ pack(), unpack()
BlobStorageBase 大規模データの外部ストレージ保存 save(), load(), delete()
StoragePolicyProtocol Blob保存の判定ポリシー should_save_as_blob()

データフロー

sequenceDiagram
  participant User as ユーザーコード
  participant Spot as core.Spot
  participant DB as TaskDB
  participant Ser as Serializer
  participant Blob as BlobStorage

  User->>Spot: fn(args)
  Spot->>DB: find_by_key(cache_key)
  alt キャッシュヒット
    DB-->>Spot: cached_data
    Spot->>Ser: unpack(data)
  else キャッシュミス
    Spot->>Spot: fn(args) 実行
    Spot->>Ser: pack(result)
    Spot->>DB: insert(metadata)
    opt Blob保存
      Spot->>Blob: save(key, data)
    end
  end
  Spot-->>User: result

技術選定

技術領域 選定 理由
メタデータDB SQLite ゼロ設定、組み込み可能、十分な性能
シリアライズ MessagePack JSONより高速・コンパクト、バイナリ対応
ストレージ ローカルファイル / クラウド 小規模はローカル、大規模は外部ストレージ等で拡張可能

非機能要件方針

2.2 キャッシュキー生成アーキテクチャ ARCH002
KEY

コンポーネント構成

graph TD
  A[core.Spot] -->|キャッシュキー生成要求| B[KeyGenPolicy]
  B -->|バインド| C[bound_keygen]
  C -->|引数別戦略| D[Strategy]
  C -->|正規化| E[canonicalize]
  C -->|ハッシュ計算| F[KeyGen.hash_items]
  E --> F

コンポーネント責務

コンポーネント 責務 インターフェース
KeyGenPolicy 関数の引数に対するハッシュ化戦略(無視、ファイル内容等)の宣言的定義と保持。 bind(func)
Strategy 引数ごとの処理方法(DEFAULT, IGNORE, FILE_CONTENT, PATH_STAT)の定義。 -
canonicalize Pythonオブジェクトを再帰的に正規化し、Msgpackで安定してシリアライズ可能な状態に変換。 @singledispatch canonicalize(obj)
KeyGen 正規化されたリストからSHA-256ハッシュを生成。レガシーデフォルトのハッシュ生成も担う。 hash_items(items), from_file_content(path)

データフロー

sequenceDiagram
  participant Spot as core.Spot
  participant KP as KeyGenPolicy
  participant Sig as inspect.signature
  participant Can as canonicalize
  participant KG as KeyGen

  Spot->>KP: bind(func)
  KP->>Sig: signature(func)
  Sig-->>KP: bound_keygen 生成
  KP-->>Spot: bound_keygen
  Spot->>Spot: bound_keygen(*args, **kwargs)
  loop 各引数
    alt Strategy.IGNORE
      Spot->>Spot: スキップ
    else Strategy.FILE_CONTENT
      Spot->>KG: from_file_content(path)
    else Strategy.PATH_STAT
      Spot->>KG: from_path_stat(path)
    else Strategy.DEFAULT
      Spot->>Can: canonicalize(val)
      Can-->>Spot: 正規化済みデータ
    end
  end
  Spot->>KG: hash_items(items_to_hash)
  KG-->>Spot: SHA-256 ハッシュ文字列 (キャッシュキー)

技術選定

技術領域 選定 理由
引数のバインド inspect.signature argsとkwargsを定義順に正確にマッピングし、デフォルト値も適用するため
正規化 functools.singledispatch 型ごとの正規化ロジックを拡張可能かつクリーンに実装するため
シリアライズ msgpack 高速でバイナリセーフであり、一貫したバイト列表現を得るため
ハッシュ関数 SHA-256 衝突確率が極めて低く、暗号学的に安全かつ広くサポートされているため

非機能要件方針

2.3 メタデータDBアーキテクチャ ARCH003
DB

コンポーネント構成

classDiagram
  class TaskDBCore {
    <<Protocol>>
    +init_schema() void
    +get(cache_key) TaskRecord
    +save(cache_key, ...) void
    +delete(cache_key) bool
  }
  class Maintenable {
    <<Protocol>>
    +delete_expired() int
    +prune(older_than) int
    +delete_all() int
  }
  class TaskDBMaintenable {
    <<Protocol>>
  }
  TaskDBCore <|-- TaskDBMaintenable
  Maintenable <|-- TaskDBMaintenable

  class SQLiteTaskDB {
    -db_path: Path
    -_write_queue: Queue
    +init_schema() void
    +get(cache_key) TaskRecord
    +save(cache_key, ...) void
  }
  TaskDBMaintenable <|-- SQLiteTaskDB

コンポーネント責務

コンポーネント 責務 インターフェース
TaskDBCore キャッシュ実行時に必要な最小限のメタデータDBアクセス init_schema(), get(), save(), delete()
Maintenable GCやCLI等、運用・保守に必要な拡張操作 delete_expired(), prune(), delete_all()
TaskDBMaintenable 実行用と保守用の両方を備えた上位Protocol TaskDBCore + Maintenable
SQLiteTaskDB SQLiteを用いたデフォルト実装。非同期書き込みキューを内包 TaskDBMaintenable 実装

データフロー

sequenceDiagram
  participant Spot as core.Spot
  participant DB as SQLiteTaskDB
  participant Q as WriteQueue
  participant Thread as WriterThread
  participant SQLite as SQLiteDB

  Spot->>DB: get(cache_key)
  DB->>SQLite: SELECT
  SQLite-->>DB: TaskRecord
  DB-->>Spot: TaskRecord

  Spot->>DB: save(metadata)
  DB->>Q: put(WriteTask)
  DB-->>Spot: void (Non-blocking)

  Thread->>Q: get()
  Thread->>SQLite: INSERT / UPDATE

技術選定

技術領域 選定 理由
デフォルトメタデータDB SQLite ゼロ設定、組み込み可能、ローカルキャッシュとして十分な性能
バックグラウンド書き込み キュー + 専用スレッド SQLiteの排他制御によるメインスレッドのブロックを防ぐため
抽象化 ProtocolベースのDI TaskDBCoreを満たせばPostgreSQL等に容易に差し替え可能

非機能要件方針

2.4 Blobストレージ構成 ARCH004
STORE

コンポーネント構成

graph TD
  A[core.Spot] -->|判定| B[StoragePolicyProtocol];
  A -->|保存/読込| C[BlobStorageBase];
  D[LocalStorage] --> C;
  E[S3Storage] --> C;
  A -->|メタデータ| F[TaskDBBase];

コンポーネント責務

コンポーネント 責務 インターフェース
StoragePolicyProtocol データのサイズ等に基づき、DB保存かBlob保存かを判定する should_save_as_blob()
BlobStorageBase 大規模データの外部ストレージ保存を抽象化する save(), load(), delete()
LocalStorage ローカルファイルシステムへのアトミックな保存と検証 base_dir, os.replace
S3Storage AWS S3互換オブジェクトストレージへの保存 s3:// URI, boto3

データフロー

sequenceDiagram
  participant Spot as core.Spot
  participant Policy as StoragePolicy
  participant DB as TaskDB
  participant Blob as BlobStorage

  Spot->>Policy: should_save_as_blob(data)
  alt Policy: True (Blob保存)
    Spot->>Blob: save(key, data)
    Blob-->>Spot: location (path/URI)
    Spot->>DB: insert(metadata, storage_type=FILE, blob_key=location)
  else Policy: False (Inline保存)
    Spot->>DB: insert(metadata, storage_type=DIRECT_BLOB, result_data=data)
  end

技術選定

技術領域 選定 理由
保存判定 閾値ベース (Threshold) DBの肥大化を防ぎつつ、小容量データのI/Oを最適化
アトミック性 一時ファイル + Rename 保存中のクラッシュや並行書き込みによる破損を完全に防止
クラウド対応 Boto3 (S3) 業界標準のプロトコルによる高い互換性とスケーラビリティ

非機能要件方針

2.5 シリアライゼーション構成 ARCH005
SERIAL

コンポーネント構成

graph TD
  A[MsgpackSerializer] -->|Registry| B[TypeRegistryProtocol]
  A -->|LRU Cache| C[Thread-Local Storage]
  A -->|Core| D[msgpack-python]

コンポーネント責務

コンポーネント 責務 インターフェース
MsgpackSerializer MessagePackベースの高速・コンパクトなバイナリ変換 dumps(), loads()
TypeRegistryProtocol ユーザー定義型(ExtType)のエンコーダ・デコーダ登録 register()
Thread-Local Cache free-threading環境でのロック競合を回避するMRO解決キャッシュ OrderedDict (LRU)

データフロー

sequenceDiagram
  participant User as ユーザーコード
  participant Ser as MsgpackSerializer
  participant Reg as TypeRegistry
  participant MP as msgpack

  User->>Ser: dumps(obj)
  Ser->>Ser: 型チェック & MRO解決
  opt カスタム型
    Ser->>Reg: エンコーダ取得
    Reg-->>Ser: encoder_fn
    Ser->>MP: ExtType(code, encoder_fn(obj))
  end
  MP-->>Ser: binary
  Ser-->>User: bytes

技術選定

技術領域 選定 理由
フォーマット MessagePack JSONより高速・コンパクト。バイナリをネイティブにサポート
スレッド安全 Copy-on-Write (CoW) 読み取りパスからロックを排除し、マルチスレッド性能を最大化
型拡張 ExtType (0-127) カスタム型を1バイトのオーバーヘッドで表現可能

非機能要件方針

2.6 バックグラウンドIO構成 ARCH006
BGIO

コンポーネント構成

graph TD
  A[core.Spot] -->|非同期タスク投入| B[_BackgroundLoop]
  B -->|Daemon Thread| C[asyncio.AbstractEventLoop]
  C -->|I/O| D[TaskDB / BlobStorage]
  A -->|ライフサイクル制御| E[atexit / ContextManager]

コンポーネント責務

コンポーネント 責務 インターフェース
_BackgroundLoop デーモンスレッドでのイベントループ管理とタスク投入 submit(), run_forever()
core.Spot 非同期保存のトリガーとエラーハンドリング _save_metadata_async()
ContextManager 処理終了時のタスク完了待機(Flush) __exit__, flush()

データフロー

sequenceDiagram
  participant Main as メインスレッド
  participant BGLoop as _BackgroundLoop
  participant Store as ストレージ

  Main->>BGLoop: submit(save_coro)
  Note over Main: 関数は即座に結果を返す (save_sync=False)
  BGLoop->>Store: 書き込み実行 (I/O)
  alt 成功
      Store-->>BGLoop: OK
  else 失敗
      BGLoop->>Main: on_background_error(error)
  end

技術選定

技術領域 選定 理由
並行処理 asyncio in Thread GILを解放しつつ、多数のI/Oタスクを効率的に多重化
スレッド種類 Daemon Thread アプリケーション終了時にプロセスをブロックしない
終了制御 atexit / drain 強制終了時も、可能な限り保留中の書き込みを完了させる

非機能要件方針

2.7 ライフサイクル管理構成 ARCH007
LIFE

コンポーネント構成

graph TD
  A[core.Spot] -->|マッチング要求| B[LifecyclePolicy]
  B -->|ルールリスト| C[Rule]
  C -->|パターン照合| D[fnmatch]
  B -->|パース| E[Retention]

コンポーネント責務

コンポーネント 責務 インターフェース
LifecyclePolicy 複数のルールを管理し、関数名に最適な有効期限を決定する resolve_with_fallback()
Rule 1つのパターンとそれに対応する保持期間のペア match(func_name)
Retention 多様な時間表現(文字列/数値)を秒数に正規化する parse_retention()

データフロー

sequenceDiagram
  participant Spot as core.Spot
  participant Policy as LifecyclePolicy
  participant DB as TaskDB

  Spot->>Policy: resolve_with_fallback("module.func")
  Policy->>Policy: ルール順次照合 (fnmatch)
  Policy-->>Spot: expires_at (timestamp)
  Spot->>DB: save(..., expires_at)
  Note over DB: get() 時に現在時刻と比較判定

技術選定

技術領域 選定 理由
パターンマッチ fnmatch (Glob) 正規表現よりも直感的で、開発者にとって馴染みのある指定方法
保持期間指定 文字列パーサー ("30d"等) 設定ファイルやデコレータでの可読性を向上
判定タイミング 遅延判定 (Lazy) 書き込み・読み込み時のオーバーヘッドを最小化

非機能要件方針

2.8 レート制限構成 ARCH008
LIMIT

コンポーネント構成

graph TD
  A["@spot.consume"] -->|宣言的適用| B[LimiterProtocol]
  C[core.Spot] -->|DI| B
  D[TokenBucket] --> B
  D -->|アルゴリズム| E[GCRA]
  D -->|時刻同期| F[monotonic clock]

コンポーネント責務

コンポーネント 責務 インターフェース
TokenBucket GCRAアルゴリズムによるスムースなトラフィック制御 consume(), consume_async()
@spot.consume 関数実行前のトークン消費を透過的に行うデコレータ cost (int or callable)
LimiterProtocol レートリミッターの差し替えを可能にするインターフェース LimiterProtocol

データフロー

sequenceDiagram
  participant User as ユーザーコード
  participant Dec as @spot.consume
  participant Bucket as TokenBucket

  User->>Dec: call func()
  Dec->>Bucket: consume(cost)
  Bucket->>Bucket: 次回実行許可時刻の計算 (GCRA)
  alt 許可
      Bucket-->>Dec: OK
      Dec->>User: execute func()
  else 拒否 (Over rate)
      Bucket-->>Dec: raise ValueError/RateLimitError
  end

技術選定

技術領域 選定 理由
アルゴリズム GCRA (Generic Cell Rate Algorithm) 固定ウィンドウと違い「スムースな」流量制御が可能
待機制御 asyncio.sleep / time.sleep 同期・非同期の両方のコンテキストで正確なスロットリングを実現
コスト計算 ダイナミックコスト 引数に応じて消費トークン数を動的に変更可能

非機能要件方針

2.9 フック機能構成 ARCH009
HOOK

コンポーネント構成

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) ユーザーが意識せずに、サブクラス化するだけで安全なフックを実装可能
実行制御 準同期実行 フック内の例外をキャッチしログ出力に留めることで、主処理を保護

非機能要件方針

2.10 メンテナンス構成 ARCH010
MAINT

コンポーネント構成

graph TD
  A[MaintenanceService] -->|操作集約| B[TaskDBBase]
  A -->|操作集約| C[BlobStorageBase]
  A -->|自動実行| D[Probabilistic Eviction]

コンポーネント責務

コンポーネント 責務 インターフェース
MaintenanceService DBとストレージを跨ぐクリーンアップ操作のファサード clean_garbage(), prune()
TaskDBBase 参照カウントや期限切れレコードの提供 get_blob_refs(), delete_expired()
BlobStorageBase 物理ファイルの列挙と削除 list_keys(), delete()

データフロー (GCプロセス)

sequenceDiagram
  participant Service as MaintenanceService
  participant DB as TaskDB
  participant Storage as BlobStorage

  Service->>DB: get_blob_refs()
  DB-->>Service: 有効な参照リスト (Whitelist)
  Service->>Storage: list_keys()
  Storage-->>Service: 全ファイルリスト
  Service->>Service: 差分抽出 (孤立ファイルの特定)
  Service->>Storage: delete(orphan_keys)
  Note over Service: 猶予期間 (grace_period) を考慮して削除

技術選定

技術領域 選定 理由
削除ポリシー ホワイトリスト方式 DBに記録がないBlobを削除対象とすることで、データの整合性を担保
競合防止 更新時刻確認 (mtime) 保存中のファイルを誤って消さないよう、一定時間経過した孤立のみ削除
実行頻度 確率的オートエビクション 書き込み時に低確率でGCをキックし、手動メンテなしでの健康度を維持

非機能要件方針

2.11 CLI構成 ARCH011
CLI

コンポーネント構成

graph TD
  A[beautyspot CLI] -->|Command| B[Typer App]
  B -->|Business Logic| C[MaintenanceService]
  B -->|Output| D[Rich Console]
  B -->|Dashboard| E[Dashboard App]

コンポーネント責務

コンポーネント 責務 インターフェース
Typer App コマンドライン引数のパースとサブコマンドのディスパッチ main(), gc(), list()
MaintenanceService 実際のキャッシュ管理ロジックの実行 clean_garbage(), clear()
Rich Console ターミナルでの視覚的に分かりやすいテーブルやパネルの描画 Console, Table
Dashboard App キャッシュ状態をインタラクティブに閲覧するためのTUI dashboard.py

データフロー

sequenceDiagram
  participant User as ユーザー
  participant CLI as CLI App
  participant Service as MaintenanceService
  participant Output as Rich Console

  User->>CLI: beautyspot gc --name my-project
  CLI->>Service: clean_garbage()
  Service-->>CLI: result (removed count, etc.)
  CLI->>Output: print summary table
  Output-->>User: formatted output

技術選定

技術領域 選定 理由
フレームワーク Typer 型ヒントに基づいた堅牢なコマンドラインインターフェースを迅速に構築
出力装飾 Rich プログレスバーやステータス表示により、長時間処理の進捗を可視化
連携 Factory DI カレントディレクトリや設定から自動的に Spot インスタンスを組み立て

非機能要件方針

2.12 依存注入構成 ARCH012
DI

コンポーネント構成

graph TD
  A[bs.Spot Factory] -->|構築| B[core.Spot]
  A -->|DI| C[TaskDBBase]
  A -->|DI| D[BlobStorageBase]
  A -->|DI| E[SerializerProtocol]
  A -->|DI| F[StoragePolicyProtocol]
  A -->|DI| G[LimiterProtocol]

コンポーネント責務

コンポーネント 責務 インターフェース
bs.Spot (Factory) 環境(名前、パス等)に応じたデフォルトコンポーネントの選定と組み立て bs.Spot()
core.Spot 注入された依存関係を使用して、キャッシュロジックをオーケストレーションする mark(), cached_run()
Protocols / ABCs 各コンポーネントが満たすべき契約(インターフェース)の定義 SerializerProtocol

技術選定

技術領域 選定 理由
パターン Constructor Injection 依存関係を明示的に渡し、テスト時のMock差し替えを容易にする
インターフェース Protocol (Duck Typing) 厳密な継承を強制せず、構造的部分型によりサードパーティ実装を受け入れ
デフォルト設定 規約より構成 (CoC) .beautyspot/ ディレクトリを基点とした標準パスを自動生成

非機能要件方針

2.13 Thundering Herd対策構成 ARCH013
HERD

コンポーネント構成

graph TD
  A[core.Spot] -->|管理要求| B[CacheManager]
  B -->|In-flight追跡| C[_inflight Dict]
  C -->|同期待機| D[threading.Event]
  C -->|非同期待機| E[asyncio.Future]

コンポーネント責務

コンポーネント責務インターフェースCacheManagerキャッシュキーごとの実行状態管理と実行のシリアライズget_or_create_inflight()_inflight実行中のタスクを保持し、後続リクエストをイベントで待機させるExecutionStatecore.Spot待機結果の受け取りとエラーの伝播cached_run()

データフロー

sequenceDiagram
  participant T1 as Thread 1 (First)
  participant T2 as Thread 2 (Second)
  participant CM as CacheManager
  participant Fn as Target Function

  T1->>CM: get_or_create(key)
  Note over CM: 新規作成 (Executor)
  T2->>CM: get_or_create(key)
  Note over CM: 既存あり (Waiter)

  T1->>Fn: execute()
  Fn-->>T1: result
  T1->>CM: set_result(key, result)
  Note over CM: Eventをセット
  CM-->>T2: notify result
  T1-->>T1: return result
  T2-->>T2: return result

技術選定

技術領域選定理由待機機構Event / FutureOS/ランタイムレベルの待機を使用し、CPU負荷(ビジーループ)を回避スコープキャッシュキー単位異なる関数の実行は妨げず、同一入力のみを直列化安全策タイムアウト & リトライ実行者がハングした場合に、待機側がデッドロックしないよう保護

非機能要件方針