active: true
derived: false
groups:
- SERIAL
header: |
  シリアライザ向けスレッドセーフなLRUキャッシュ
level: 1.41
links:
- ARCH005: f7IpeWL9LR7SQ3LP4FNILP4SUho1yMVkYhHP8_dKm8Y=
- REQ005: iMDbh51FT-Eu8XByvRDwGCzvXD7iYGh6c5AwH9v0RxA=
normative: true
ref: ''
reviewed: WKDn6yUjeO-MjeyyutpeSBJAEU7U28fGIAn-W_ydnJU=
status: accepted
text: |
  # シリアライザ向けスレッドセーフなLRUキャッシュ

  ## コンテキストと課題

  `MsgpackSerializer` は動的型生成時のメモリリークを防ぐために、内部で `OrderedDict` を用いた LRU キャッシュを運用しています。しかし、バックグラウンド保存や Web フレームワークでの利用など、マルチスレッド環境からの並行アクセスが日常的に発生します。ロックを持たない `OrderedDict` への並行操作は、`RuntimeError` やデータの破損を引き起こす致命的なバグの温床となっていました。

  ## 判断基準

  * **Stability**: マルチスレッド環境下での並行アクセスによるクラッシュやデータ破損を完全に排除すること。
  * **Reliability**: デバッグ困難な稀に発生する競合状態を未然に防ぎ、ライブラリの信頼性を高めること。
  * **Performance**: ロックの範囲を最小限に留め、シリアライズ処理全体のスループットへの影響を最小化すること。

  ## 検討した選択肢

  * **Option 1**: 引き続きロックフリーなアプローチをとり、エラー発生時にリトライする。
  * **Option 2**: `threading.Lock()` を導入し、キャッシュ操作を排他的に行う。

  ## 決定事項

  採用した選択肢: **Option 2**.

  `MsgpackSerializer` の内部状態（キャッシュおよびレジストリ）に対するすべての読み書き操作を `threading.Lock()` で保護します。

  1. **安定性の優先**: 確実な排他制御により、マルチスレッド下での信頼性を担保します。
  2. **限定的なロック範囲**: ロックの範囲を「型の解決とキャッシュの更新」というメモリアクセス領域に限定し、重いシリアライズ処理（I/O や計算）はロック外で実行します。

  ## 影響・結果

  * **ポジティブ**:
      * `MsgpackSerializer` をシングルトンとして安全にマルチスレッド環境で使い回せるようになった。
      * 競合状態に起因する非決定的なクラッシュを排除できた。
  * **ネガティブ**:
      * キャッシュアクセスごとにロック取得のオーバーヘッドが追加されるが、実用上のパフォーマンスインパクトは極めて軽微である。
