generated from amazon-archives/__template_MIT-0
-
Notifications
You must be signed in to change notification settings - Fork 38
Closed
Labels
bugSomething isn't workingSomething isn't workingpriority: highNeeds prompt attentionNeeds prompt attention
Milestone
Description
概要
webapp/src/lib/prisma.ts と cdk/lib/constructs/database.ts に複数の問題があります。
- セキュリティ問題:
console.log(process.env.DATABASE_URL)でDB接続文字列(パスワード含む)がCloudWatch Logsに出力される - リトライ機構なし: Aurora Serverless v2の
idle_session_timeout(60秒)後の接続切断でクエリが失敗し、自動復旧しない - 接続オプション不十分:
pool_timeout=20はLambda長時間実行(最大15分)に不適、connect_timeout=20はAurora Serverless v2のcold start(auto-pauseからの復帰、最大30秒)に不十分
現在のコード
prisma.ts:
console.log(process.env.DATABASE_URL); // パスワードがログに出力される
export const prisma = globalForPrisma.prisma || new PrismaClient({ log: ['query', 'info', 'warn', 'error'] });database.ts:
const option = '?pool_timeout=20&connect_timeout=20';修正案
1. prisma.ts — console.log削除 + リトライ拡張追加
import { Prisma, PrismaClient } from '@prisma/client';
const globalForPrisma = global as unknown as {
prisma: PrismaClient;
};
function isRetryableError(error: unknown): boolean {
if (!(error instanceof Error)) return false;
const msg = error.message;
const code = (error as { code?: string }).code;
return (
code === 'P2024' || // Connection pool timeout
code === 'P1001' || // Can't reach database
code === 'P1017' || // Server has closed the connection
code === 'P2034' || // Transaction conflict
msg.includes('idle-session timeout') ||
msg.includes('terminating connection') ||
msg.includes('57P05') ||
msg.includes('ECONNRESET') ||
msg.includes('Connection reset') ||
msg.includes('Connection refused') ||
msg.includes('Connection terminated') ||
msg.includes("Can't reach database server")
);
}
// 注意: PrismaClientInitializationErrorを名前だけで判定しない。
// 認証エラー等の永続的失敗もこの型で返るため、メッセージベースで判定する。
const basePrisma = new PrismaClient();
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 5, baseDelay = 500): Promise<T> {
let lastError: unknown;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (attempt === maxRetries || !isRetryableError(error)) throw error;
await basePrisma.$disconnect();
const delay = Math.round(baseDelay * Math.pow(2, attempt) + Math.random() * 100);
await new Promise((r) => setTimeout(r, delay));
}
}
throw lastError;
}
const retryExtension = Prisma.defineExtension({
name: 'retry-on-connection-error',
query: {
$allModels: {
async $allOperations({ args, query }) {
return withRetry(() => query(args));
},
},
},
});
export const prisma = basePrisma.$extends(retryExtension) as unknown as PrismaClient;
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;設計上の注意点:
$connect()を即時実行しないこと。PrismaClientは最初のクエリ時に自動接続する。即時接続するとLambdaコールドスタートのたびにAuroraがresumeされ、DBクエリを必要としないリクエスト(sign-inページ等)でもコストが発生するPrismaClientInitializationErrorを型名だけで判定すると、認証エラー(永続的失敗)もリトライされ、80秒の遅延が発生する
2. database.ts — 接続オプション最適化 + Data API有効化 + 接続ログ
// 接続オプション変更
const option = '?connection_limit=1&pool_timeout=0&connect_timeout=30';
// connection_limit=1: Lambda並列実行時のDB接続枯渇を防止
// pool_timeout=0: 長時間実行Lambda(最大15分)でタイムアウトしない
// connect_timeout=30: Aurora Serverless v2 cold start考慮(最大30秒)DatabaseClusterに以下を追加:
enableDataApi: true,
cloudwatchLogsExports: ['postgresql'],
cloudwatchLogsRetention: logs.RetentionDays.ONE_WEEK,
parameterGroup: new rds.ParameterGroup(this, 'ParameterGroup', {
engine,
parameters: {
idle_session_timeout: '60000',
log_connections: '1',
log_disconnections: '1',
},
}),- Data API: CLIから直接SQLを実行でき、運用時のデバッグ・データ修正が容易になる
- 接続ログ: Aurora auto-pauseからの意図しないresumeの原因調査に必須
検証方法
-
console.log(process.env.DATABASE_URL)が削除されていること - Aurora auto-pause後の最初のリクエストがリトライで自動復旧すること
- 認証エラー(永続的失敗)がリトライされず即座にエラーを返すこと
- RDS Data APIでCLIからSQLを実行できること
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingpriority: highNeeds prompt attentionNeeds prompt attention