Render Manual Scaling対応のため、PostgreSQLベースのセッション管理システムを実装し、複数インスタンス間でセッションデータを共有する機能について
Render Manual Scaling対応のため、PostgreSQLベースのセッション管理システムを実装しました。この記事では、複数インスタンス間でセッションデータを共有する機能の実装と、開発を通じて学んだことについて解説します。
medicine-recommend-system では、Render Manual Scalingを使用する場合に複数のインスタンスが起動します。しかし、Flaskのデフォルトのセッション管理(メモリベース)では、インスタンス間でセッションデータが共有されないという問題がありました。同じユーザーが別リクエストで別インスタンスに振られると、会話履歴やユーザー属性が引き継がれず、体験が分断されます。
PostgreSQLベースのセッション管理システムを実装し、複数インスタンス間でセッションデータを共有できるようにしました。READMEでは、2〜3台のインスタンスで同時接続15台に対応できる構成として言及されています。
現在の medicine-recommend-system では、セッションとグローバル状態は src/services/database.py(DatabaseManager)と src/services/session_manager.py で扱っています。テーブル作成は起動時の initialize_tables() で行われます。
# src/services/database.py の initialize_tables() より抜粋
create_sessions_table_sql = """
CREATE TABLE IF NOT EXISTS sessions (
session_id VARCHAR(255) PRIMARY KEY,
username VARCHAR(255),
messages JSONB,
user_attributes JSONB,
last_activity TIMESTAMP NOT NULL,
client_ip VARCHAR(255),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
session_active BOOLEAN DEFAULT TRUE
);
"""
create_global_state_table_sql = """
CREATE TABLE IF NOT EXISTS global_state (
key VARCHAR(255) PRIMARY KEY,
value JSONB NOT NULL,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
"""
インデックスは idx_sessions_last_activity、idx_global_state_updated_at などが定義されています。
アプリからは session_manager の API を利用します。内部で get_database() により DatabaseManager を取得し、db.save_session / db.get_session を呼びます。
# src/services/session_manager.py
def get_session_from_db(session_id):
"""セッションをDBから取得、失敗時はメモリフォールバック"""
db = get_database()
if db and (db.connection or db.connection_pool):
session_data = db.get_session(session_id)
if session_data:
return session_data
return _all_sessions.get(session_id)
def save_session_to_db(session_id, data):
"""セッションをDBに保存、失敗時はメモリに保存"""
db = get_database()
if db and (db.connection or db.connection_pool):
success = db.save_session(session_id, data)
if success:
return True
_all_sessions[session_id] = data
logger.warning(f"DB save failed, using memory fallback for session {session_id}")
return True
AI_AUTO_REPLY・ADMIN_MODE・MANUAL_REPLY_QUEUE・MANUAL_REPLY_MESSAGE は、global_state テーブルの key/value(JSONB)で管理されています。session_manager からは次のように取得・設定します。
# src/services/session_manager.py
def get_manual_reply_queue():
"""手動返信キューをDBから取得"""
db = get_database()
if db and (db.connection or db.connection_pool):
return db.get_global_state('MANUAL_REPLY_QUEUE', default_value=[])
return _manual_reply_queue
def set_manual_reply_queue(value):
"""手動返信キューをDBに保存"""
global _manual_reply_queue
db = get_database()
if db and (db.connection or db.connection_pool):
db.set_global_state('MANUAL_REPLY_QUEUE', value)
_manual_reply_queue = value
DB 接続が利用できない場合は、モジュール変数 _all_sessions や _manual_reply_queue などにフォールバックし、単一インスタンスとして動作し続ける設計です。
session_manager 内でメモリフォールバックし、logger.warning("DB save failed, using memory fallback for session ...") がログに出力されます。本番ではDB(Neon PostgreSQL)を利用しているため、接続が一時的に不安定になった場合にのみフォールバックが発生し得ます。ログでフォールバックの有無を確認し、Neonの接続制限やネットワークを確認する運用にしています。複数インスタンス間でセッションデータを共有する際、競合状態の処理に苦労しました。同じセッションに対して複数のインスタンスが同時に書き込みを行う場合、データの整合性を保つ必要があります。
解決策:
DBへのアクセスが頻繁になると、パフォーマンスが低下する可能性があります。
解決策:
DB接続失敗時は、メモリベースの動作にフォールバックする必要があります。
解決策:
原因: DB接続失敗時にメモリベースにフォールバックし、インスタンスが再起動されるとデータが失われる
解決策:
原因: DBへのアクセスが頻繁になり、レスポンス時間が長くなる
解決策:
原因: 複数のインスタンスが同じセッションに対して同時に書き込みを行う
解決策:
リポジトリのREADMEでは、マルチインスタンス対応は次のように整理されています。
なお、2026年2月には GCP Cloud Run および Neon PostgreSQL へ移行しています。Cloud Run ではインスタンスのスケールやマルチインスタンスの扱いがRenderと異なりますが、セッションとグローバル状態をDBに置く設計はそのまま活きており、どの実行環境でも一貫した動作を保つ基盤になっています。
マルチインスタンス対応の実装により、複数インスタンス間でセッションデータを共有できるようになりました。PostgreSQLベースのセッション管理システムにより、スケーラビリティが向上し、2〜3台のインスタンスで同時接続15台に対応できるようになりました。
分散システムの難しさを実感しながらも、継続的な改善により、より堅牢なシステムを構築できました。
今後も、Cloud Run / Neon 環境に合わせたチューニングや、より効率的なセッション管理の検討を続けていきます。
API呼び出し回数を約67%削減し、翻訳速度を10-20倍高速化したパフォーマンス最適化の実装について
RenderからGCP Cloud Runへの移行、Neon PostgreSQLへの移行、GitHub連携による継続的デプロイの実装について
医療情報システムの開発において、倫理的な配慮がどのように実装に反映されるかを、チャット型医薬品相談ツールの経験から解説します。
WCAG AA準拠のアクセシビリティ機能、音声読み上げ、文字サイズ調整、多言語対応など、すべてのユーザーが使いやすいUI/UXの実装について
性被害を受けた方に対して、72時間以内の緊急避妊薬の服用の重要性を強調し、対面診療とオンライン診療の案内、心理的サポートと警察への相談の案内を提供する機能の実装について
推奨医薬品リスト内で成分重複をチェックし、深刻度レベル別の警告を表示する機能の実装について