Skip to content

Commit

Permalink
Production 환경에서의 DB 자동 Migration 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
kmc7468 committed Jan 20, 2025
1 parent ce32989 commit 8031106
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 23 deletions.
15 changes: 8 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
FROM node:22-alpine AS base
WORKDIR /app

RUN apk add --no-cache bash curl && \
curl -o /usr/local/bin/wait-for-it https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh && \
chmod +x /usr/local/bin/wait-for-it

RUN npm install -g pnpm@9
COPY pnpm-lock.yaml .

Expand All @@ -10,10 +14,9 @@ FROM base AS build
RUN pnpm fetch

COPY . .
RUN pnpm install --offline
RUN pnpm build

RUN sed -i "s/http\.createServer()/http.createServer({ requestTimeout: 0 })/g" ./build/index.js
RUN pnpm install --offline && \
pnpm build && \
sed -i "s/http\.createServer()/http.createServer({ requestTimeout: 0 })/g" ./build/index.js

# Deploy Stage
FROM base
Expand All @@ -23,9 +26,7 @@ COPY package.json .
RUN pnpm install --offline --prod

COPY --from=build /app/build ./build
COPY drizzle ./drizzle

EXPOSE 3000
ENV BODY_SIZE_LIMIT=Infinity

CMD ["node", "./build/index.js"]
CMD ["bash", "-c", "wait-for-it ${DATABASE_HOST:-localhost}:${DATABASE_PORT:-5432} -- node ./build/index.js"]
1 change: 1 addition & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ services:
database:
image: postgres:17.2-alpine
restart: on-failure
user: ${CONTAINER_UID:-0}:${CONTAINER_GID:-0}
volumes:
- ./data/database:/var/lib/postgresql/data
environment:
Expand Down
6 changes: 3 additions & 3 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import type { ServerInit } from "@sveltejs/kit";
import { sequence } from "@sveltejs/kit/hooks";
import schedule from "node-schedule";
import { cleanupExpiredUserClientChallenges } from "$lib/server/db/client";
import { migrateDB } from "$lib/server/db/drizzle";
import { migrateDB } from "$lib/server/db/kysely";
import {
cleanupExpiredSessions,
cleanupExpiredSessionUpgradeChallenges,
} from "$lib/server/db/session";
import { authenticate, setAgentInfo } from "$lib/server/middlewares";

export const init: ServerInit = () => {
migrateDB();
export const init: ServerInit = async () => {
await migrateDB();

schedule.scheduleJob("0 * * * *", () => {
cleanupExpiredUserClientChallenges();
Expand Down
4 changes: 2 additions & 2 deletions src/lib/server/db/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DatabaseError } from "pg";
import pg from "pg";
import { IntegrityError } from "./error";
import db from "./kysely";
import type { UserClientState } from "./schema";
Expand Down Expand Up @@ -91,7 +91,7 @@ export const createUserClient = async (userId: number, clientId: number) => {
try {
await db.insertInto("user_client").values({ user_id: userId, client_id: clientId }).execute();
} catch (e) {
if (e instanceof DatabaseError && e.code === "23505") {
if (e instanceof pg.DatabaseError && e.code === "23505") {
throw new IntegrityError("User client already exists");
}
throw e;
Expand Down
4 changes: 2 additions & 2 deletions src/lib/server/db/hsk.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DatabaseError } from "pg";
import pg from "pg";
import { IntegrityError } from "./error";
import db from "./kysely";
import type { HskState } from "./schema";
Expand Down Expand Up @@ -40,7 +40,7 @@ export const registerInitialHsk = async (
})
.execute();
} catch (e) {
if (e instanceof DatabaseError && e.code === "23505") {
if (e instanceof pg.DatabaseError && e.code === "23505") {
throw new IntegrityError("HSK already registered");
}
throw e;
Expand Down
35 changes: 31 additions & 4 deletions src/lib/server/db/kysely.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Kysely, PostgresDialect } from "kysely";
import { Pool } from "pg";
import { Kysely, PostgresDialect, Migrator } from "kysely";
import pg from "pg";
import env from "$lib/server/loadenv";
import migrations from "./migrations";
import type { Database } from "./schema";

const dialect = new PostgresDialect({
pool: new Pool({
pool: new pg.Pool({
host: env.database.host,
port: env.database.port,
user: env.database.user,
Expand All @@ -15,6 +16,32 @@ const dialect = new PostgresDialect({

const db = new Kysely<Database>({ dialect });

// TODO: Migration
export const migrateDB = async () => {
if (env.nodeEnv !== "production") return;

const migrator = new Migrator({
db,
provider: {
async getMigrations() {
return migrations;
},
},
});
const { error, results } = await migrator.migrateToLatest();
if (error) {
const migration = results?.find(({ status }) => status === "Error");
if (migration) {
console.error(`Migration "${migration.migrationName}" failed.`);
}
console.error(error);
process.exit(1);
}

if (results?.length === 0) {
console.log("Database is up-to-date.");
} else {
console.log("Database migration completed.");
}
};

export default db;
4 changes: 2 additions & 2 deletions src/lib/server/db/mek.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DatabaseError } from "pg";
import pg from "pg";
import { IntegrityError } from "./error";
import db from "./kysely";
import type { MekState } from "./schema";
Expand Down Expand Up @@ -52,7 +52,7 @@ export const registerInitialMek = async (
})
.execute();
} catch (e) {
if (e instanceof DatabaseError && e.code === "23505") {
if (e instanceof pg.DatabaseError && e.code === "23505") {
throw new IntegrityError("MEK already registered");
}
throw e;
Expand Down
5 changes: 5 additions & 0 deletions src/lib/server/db/migrations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as Initial1737357000 from "./1737357000-Initial";

export default {
"1737357000-Initial": Initial1737357000,
};
6 changes: 3 additions & 3 deletions src/lib/server/db/session.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DatabaseError } from "pg";
import pg from "pg";
import env from "$lib/server/loadenv";
import { IntegrityError } from "./error";
import db from "./kysely";
Expand All @@ -25,7 +25,7 @@ export const createSession = async (
})
.execute();
} catch (e) {
if (e instanceof DatabaseError && e.code === "23505") {
if (e instanceof pg.DatabaseError && e.code === "23505") {
throw new IntegrityError("Session already exists");
}
throw e;
Expand Down Expand Up @@ -105,7 +105,7 @@ export const registerSessionUpgradeChallenge = async (
})
.execute();
} catch (e) {
if (e instanceof DatabaseError && e.code === "23505") {
if (e instanceof pg.DatabaseError && e.code === "23505") {
throw new IntegrityError("Challenge already registered");
}
throw e;
Expand Down
1 change: 1 addition & 0 deletions src/lib/server/loadenv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ if (!building) {
}

export default {
nodeEnv: env.NODE_ENV || "development",
database: {
host: env.DATABASE_HOST,
port: env.DATABASE_PORT ? parseInt(env.DATABASE_PORT, 10) : undefined,
Expand Down

0 comments on commit 8031106

Please sign in to comment.