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>
This commit is contained in:
kappa
2026-01-28 20:26:23 +09:00
parent 5ba555864a
commit 7ef0ec7594
5 changed files with 258 additions and 0 deletions

View File

@@ -0,0 +1,161 @@
# 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`
```sql
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**:
```typescript
// 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
```bash
# 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
```sql
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
- [x] Migration SQL syntax validated
- [x] Schema.sql updated
- [x] All code references updated (env.SESSION_KV → env.DB)
- [x] 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