apps/web/instrumentation.node.ts
Rama main · réplica de lectura del repositorio original.
// This file is used to run database migrations in the docker builds or other self hosting environments.
// It is not suitable (a.k.a DEADLY) for serverless environments where the server will be restarted on each request.
//
import {
BucketAlreadyOwnedByYou,
CreateBucketCommand,
PutBucketPolicyCommand,
S3Client,
} from "@aws-sdk/client-s3";
import { migrateDb } from "@cap/database/migrate";
import { buildEnv, serverEnv } from "@cap/env";
export async function register() {
if (process.env.NEXT_PUBLIC_IS_CAP) return;
// Exit, not throw: Next.js catches a throwing register() and serves 500s.
try {
serverEnv();
} catch {
console.error("🚨 Environment validation failed, exiting");
process.exit(1);
}
console.log("Waiting 5 seconds to run migrations");
// Function to trigger migrations with retry logic
const triggerMigrations = async (retryCount = 0, maxRetries = 3) => {
try {
await runMigrations();
} catch (error) {
console.error(
`🚨 Error triggering migrations (attempt ${retryCount + 1}):`,
error,
);
if (retryCount < maxRetries - 1) {
console.log(
`🔄 Retrying in 5 seconds... (${retryCount + 1}/${maxRetries})`,
);
setTimeout(() => triggerMigrations(retryCount + 1, maxRetries), 5000);
} else {
console.error(`🚨 All ${maxRetries} migration attempts failed.`);
process.exit(1); // Exit with error code if all attempts fail
}
}
};
// Add a timeout to trigger migrations after 5 seconds on server start
setTimeout(() => triggerMigrations(), 5000);
setTimeout(() => createS3Bucket(), 5000);
}
async function createS3Bucket() {
const s3Client = new S3Client({
endpoint: serverEnv().S3_INTERNAL_ENDPOINT,
region: serverEnv().CAP_AWS_REGION,
credentials: {
accessKeyId: serverEnv().CAP_AWS_ACCESS_KEY ?? "",
secretAccessKey: serverEnv().CAP_AWS_SECRET_KEY ?? "",
},
forcePathStyle: serverEnv().S3_PATH_STYLE,
});
await s3Client
.send(new CreateBucketCommand({ Bucket: serverEnv().CAP_AWS_BUCKET }))
.then(() => {
console.log("Created S3 bucket");
return s3Client.send(
new PutBucketPolicyCommand({
Bucket: serverEnv().CAP_AWS_BUCKET,
Policy: JSON.stringify({
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Principal: "*",
Action: ["s3:GetObject"],
Resource: [`arn:aws:s3:::${serverEnv().CAP_AWS_BUCKET}/*`],
},
],
}),
}),
);
})
.then(() => {
console.log("Configured S3 buckeet");
})
.catch((e) => {
if (e instanceof BucketAlreadyOwnedByYou) {
console.log("Found existing S3 bucket");
return;
}
});
}
async function runMigrations() {
const isDockerBuild = buildEnv.NEXT_PUBLIC_DOCKER_BUILD === "true";
if (isDockerBuild) {
try {
console.log("🔍 DB migrations triggered");
console.log("💿 Running DB migrations...");
await migrateDb();
console.log("💿 Migrations run successfully!");
} catch (error) {
console.error("🚨 MIGRATION_FAILED", { error });
throw error;
}
}
}