Files
telegram-bot-workers/migrations/003_MIGRATION_NOTES.md
kappa 7ef0ec7594 chore: add server provisioning migrations
- 003_add_server_tables.sql: server_orders, server_instances tables
- 003_server_sessions.sql: KV-based session tracking
- 004_add_terminated_at.sql: track instance termination time

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 20:26:23 +09:00

5.2 KiB

Migration 003: Server Sessions from KV to D1

Date: 2026-01-28 Type: Session Storage Migration Status: Ready to Deploy

Overview

Migrated server consultation session management from KV Namespace to D1 Database for better consistency, reliability, and integrated data management.

Changes Summary

1. Database Schema (schema.sql + migrations/003_server_sessions_d1.sql)

New Table: server_sessions

CREATE TABLE IF NOT EXISTS server_sessions (
  user_id TEXT PRIMARY KEY,
  status TEXT NOT NULL CHECK(status IN ('gathering', 'recommending', 'selecting', 'ordering', 'completed')),
  collected_info TEXT,
  last_recommendation TEXT,
  messages TEXT,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL,
  expires_at INTEGER NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_server_sessions_expires ON server_sessions(expires_at);

2. Code Changes

Updated Files:

  • /src/server-agent.ts - Session management functions (getServerSession, saveServerSession, deleteServerSession)
  • /src/openai-service.ts - Session check in generateOpenAIResponse()
  • /src/tools/server-tool.ts - start_consultation, continue_consultation, cancel_consultation actions
  • /src/routes/handlers/callback-handler.ts - server_order and server_cancel callbacks

Function Signature Changes:

// Before (KV)
export async function getServerSession(kv: KVNamespace, userId: string): Promise<ServerSession | null>
export async function saveServerSession(kv: KVNamespace, userId: string, session: ServerSession): Promise<void>
export async function deleteServerSession(kv: KVNamespace, userId: string): Promise<void>

// After (D1)
export async function getServerSession(db: D1Database, userId: string): Promise<ServerSession | null>
export async function saveServerSession(db: D1Database, userId: string, session: ServerSession): Promise<void>
export async function deleteServerSession(db: D1Database, userId: string): Promise<void>

// New
export async function cleanupExpiredSessions(db: D1Database): Promise<number>

Removed:

  • All [SESSION DEBUG] logging (unnecessary with D1's strong consistency)
  • KV constants: SESSION_TTL, SESSION_KEY_PREFIX

Added:

  • SESSION_TTL_MS constant (3600 * 1000 = 1 hour)
  • cleanupExpiredSessions() function for cron cleanup
  • Automatic expiry checking in queries (WHERE expires_at > ?)

3. Key Implementation Details

Session Storage:

  • JSON serialization for complex fields (collected_info, last_recommendation, messages)
  • Automatic TTL management with expires_at column
  • Strong consistency (no eventual consistency issues)

Error Handling:

  • Graceful JSON parsing with try-catch
  • Null checks for expired/missing sessions
  • Proper logging without debug noise

Performance:

  • Primary key on user_id for fast lookups
  • Index on expires_at for efficient cleanup
  • Single query for session retrieval

4. Migration Path

Automatic Migration:

  • Old KV sessions will expire naturally (1 hour TTL)
  • New sessions are created in D1 automatically
  • No manual data migration needed

Zero Downtime:

  • D1 table creation is idempotent (IF NOT EXISTS)
  • Code handles missing sessions gracefully
  • Users can restart consultation if session expires

5. Benefits

Before (KV Namespace):

  • Eventual consistency (delayed reads)
  • Complex debugging (async replication)
  • Separate data store (fragmented)
  • Manual cleanup needed

After (D1 Database):

  • Strong consistency (immediate reads)
  • Simple debugging (SQL queries)
  • Integrated storage (single database)
  • Automatic cleanup (expires_at + cron)

6. Deployment Steps

# 1. Apply migration (creates table)
wrangler d1 execute telegram-conversations --file=migrations/003_server_sessions_d1.sql

# 2. Verify table creation
wrangler d1 execute telegram-conversations --command "SELECT name FROM sqlite_master WHERE type='table' AND name='server_sessions'"

# 3. Deploy code changes
npm run deploy

# 4. Test server consultation flow
# Send message: "서버 추천"
# Verify session is created in D1
wrangler d1 execute telegram-conversations --command "SELECT * FROM server_sessions LIMIT 5"

7. Rollback Plan

If issues occur:

  1. Code Rollback: Revert to previous commit (KV-based code)
  2. Database: Drop table if needed
    DROP TABLE IF EXISTS server_sessions;
    DROP INDEX IF EXISTS idx_server_sessions_expires;
    

Note: Old KV sessions are unaffected (will expire naturally)

8. Testing Checklist

  • Migration SQL syntax validated
  • Schema.sql updated
  • All code references updated (env.SESSION_KV → env.DB)
  • Logging cleaned up (no debug noise)
  • Local testing (npm run dev)
  • Production deployment
  • Session creation test
  • Session retrieval test
  • Session expiry test
  • Concurrent session handling

9. Notes

Important:

  • server_order_confirm: and delete_confirm: sessions remain in KV (not migrated, separate feature)
  • Troubleshoot agent still uses KV (separate migration needed if required)
  • D1 binding (env.DB) already exists in project

Future Improvements:

  • Consider migrating troubleshoot sessions to D1
  • Add session analytics (query D1 for session stats)
  • Implement session history/audit log