Solusi Masalah Praktis Setelah Deploy di Infrastruktur PaaS Serverless
TuBrief 편집팀
2026년 7월 24일
0
Internet Technology원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
커뮤니티의 다른 글
댓글 (0)
Log in to leave a comment
아직 작성된 글이 없습니다
원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
Log in to leave a comment
아직 작성된 글이 없습니다
PaaS all-in-one yang memungkinkan Anda melakukan deploy frontend dan backend hanya dengan beberapa klik terlihat sempurna pada awalnya. Masalah baru muncul setelah pengguna yang sebenarnya mulai berdatangan. Kode yang berjalan sangat lancar di lingkungan lokal mendadak menghasilkan error timeout begitu naik ke produksi, dan mencoba mengubah satu schema DB saja bisa membuat seluruh layanan mati total. Ditambah lagi, saat terjebak dalam posisi vendor lock-in yang membuat Anda serba salah, pusing pun makin menjadi-jadi.
Berikut adalah beberapa pola infrastruktur yang dirangkum untuk menyingkirkan hambatan-hambatan tersebut dengan rapi, sambil tetap menikmati kenyamanan dari platform semacam ini.
Proses Node.js di lingkungan lokal terus menyala, tetapi lingkungan serverless hanya muncul sejenak saat ada permintaan masuk dan kemudian menghilang. Jika Anda secara asal-asalan menetapkan variabel global atau koneksi singleton DB pada momen cold start, pool koneksi akan mengering dalam sekejap.
Anda tentu tidak mungkin selalu mengeceknya dengan melakukan deploy ke server staging setiap saat. Mengisolasi layer jaringan itu sendiri di lingkungan lokal dan menjalankan handler jauh lebih cepat.
`typescript
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/api/v1/user/profile', ({ request }) => {
const authHeader = request.headers.get('Authorization');
if (!authHeader) {
return new HttpResponse(null, { status: 401, statusText: 'Unauthorized' });
}
return HttpResponse.json({
id: 'usr_102938',
email: 'dev@example.com',
role: 'ADMIN',
createdAt: new Date().toISOString()
});
})
];
// src/mocks/node.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);
`
Proses untuk menerapkan pola ini sangat sederhana.
setupServer saat menjalankan emulator..env.local dari endpoint transaction pooler produksi.Tanpa perlu menekan tombol deploy, Anda dapat memverifikasi perilaku antarmuka backend secara 100% identik di lingkungan lokal. Ini adalah struktur yang mendapatkan umpan balik secara instan setelah kode ditulis, tanpa membuang-buang waktu untuk pengujian jarak jauh yang tidak stabil.
Saat menggunakan PostgreSQL serverless seperti Supabase atau Neon, mengeksekusi perintah ALTER TABLE secara langsung adalah hal yang berbahaya. Lock ACCESS EXCLUSIVE akan terpasang pada tabel target, membuat query-query berikutnya berada dalam status antrean berturut-turut, yang pada akhirnya menyebabkan gangguan timeout.
Pertama-tama, batasan timeout harus diterapkan pada sesi migrasi.
`sql
SET lock_timeout = '2000ms';
SET statement_timeout = '5000ms';
ALTER TABLE users ADD COLUMN bio VARCHAR(255);
`
Untuk mengubah struktur DB yang sedang beroperasi secara aman, Anda harus menggunakan metode memperluas kode dan DB secara bersamaan, kemudian mengikis hal-hal yang lama secara bertahap.
`typescript
import { db } from './db';
interface UpdateUserProfileInput {
userId: string;
fullName: string;
}
export async function updateUserProfile({ userId, fullName }: UpdateUserProfileInput) {
await db.transaction(async (tx) => {
await tx.user.update({
where: { id: userId },
data: {
full_name: fullName,
name: fullName
}
});
});
}
`
Tiga langkah untuk pekerjaan yang aman.
lock_timeout agar pekerjaan segera dihentikan saat terjadi persaingan lock.Dengan mematuhi prosedur ini, Anda dapat mengganti schema tanpa melewatkan satu pun permintaan dari pengguna.
Dalam lingkungan serverless, jika Anda hanya menyisakan console.log, log dari berbagai instance akan bercampur aduk dan menjadi kacau. Request ID yang unik dan format JSON yang terstruktur sangat esensial untuk melacak alur mulai dari saat satu permintaan masuk hingga keluar.
`typescript
import { Hono } from 'hono';
import { requestId } from 'hono/request-id';
import pino from 'pino';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
formatters: {
level: (label) => ({ level: label.toUpperCase() })
},
base: { env: process.env.NODE_ENV }
});
const app = new Hono();
app.use('', requestId());
app.use('', async (c, next) => {
const reqId = c.var.requestId;
const startTime = performance.now();
c.set('logger', logger.child({ reqId }));
await next();
const durationMs = Math.round(performance.now() - startTime);
logger.info({
reqId,
method: c.req.method,
path: c.req.path,
status: c.res.status,
durationMs
}, 'Request processing finished');
});
`
Berikut adalah pengaturan untuk menghindari lonjakan biaya akibat melampaui batas saat menggunakan tool pemantauan eksternal.
Server-Timing ke dalam response header untuk mengirimkan titik bottleneck ke sistem pemantauan.`typescript
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1,
beforeSend(event, hint) {
const error = hint.originalException;
if (error && error instanceof Error && error.message.includes('ECONNRESET')) {
return null;
}
return event;
}
});
`
Dengan memilah log 200 OK yang tidak berarti dan situasi pengecualian yang bersifat noise saja, Anda sudah dapat mengontrol sistem secara cukup baik di dalam batas tier gratis platform pemantauan.
Mengkoneksikan SDK khusus PaaS tertentu secara langsung ke logika bisnis akan membuat Anda harus membongkar dan mengganti seluruh kode saat akan pindah ke platform lain di kemudian hari. Itulah alasan mengapa kita menggunakan Adapter Pattern yang dirangkum oleh Martin Fowler untuk memisahkan titik temu antara logika inti aplikasi dan SDK cloud eksternal.
`typescript
export interface IStorageService {
uploadFile(path: string, fileBuffer: Buffer, mimeType: string): Promise<{ url: string }>;
deleteFile(path: string): Promise;
}
import { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';
export class S3StorageAdapter implements IStorageService {
private s3: S3Client;
private bucket: string;
constructor(region: string, bucket: string) {
this.s3 = new S3Client({ region });
this.bucket = bucket;
}
async uploadFile(path: string, fileBuffer: Buffer, mimeType: string): Promise<{ url: string }> {
await this.s3.send(new PutObjectCommand({
Bucket: this.bucket,
Key: path,
Body: fileBuffer,
ContentType: mimeType
}));
return { url: https://${this.bucket}.s3.amazonaws.com/${path} };
}
async deleteFile(path: string): Promise {
await this.s3.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: path }));
}
}
`
Otomatiskan juga backup data agar Anda dapat berpindah kapan saja.
`bash
#!/usr/bin/env bash
set -euo pipefail
TIMESTAMP=(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/tmp/db_backup_{TIMESTAMP}"
S3_BUCKET="s3://my-app-exit-backups/pg_dumps"
export PGPASSWORD="${DB_PASSWORD}"
mkdir -p "${BACKUP_DIR}"
pg_dump -h "{DB_PORT}" -U "{DB_NAME}"
-Fc --exclude-table-data='logs_*' > "${BACKUP_DIR}/full_schema_data.dump"
tar -czvf "{BACKUP_DIR}" .
aws s3 cp "{S3_BUCKET}/{R2_ENDPOINT_URL}"
rm -rf "{BACKUP_DIR}.tar.gz"
`
pg_dump untuk mengekstrak schema dan data.crontab agar file backup dikirimkan ke Cloudflare R2 atau bucket S3 eksternal.Dengan mengurangi risiko terikat pada platform tertentu, Anda akan jauh lebih mudah untuk mengatasi masalah kenaikan biaya unit infrastruktur maupun saat terjadi gangguan pada platform.