sst / sst

Build full-stack apps on your own infrastructure.
https://sst.dev
MIT License
24.04k stars 1.85k forks source link

Single RDS instance with multiple databases #5879

Open pikonha opened 1 month ago

pikonha commented 1 month ago

I have an architecture of 5 microservices, each requiring its database. I now need a way to reuse the same RDS instance created by the Postgres resource, but dynamically creating a database for each of the services, which are going to increase in number over time (reach around 80 at the end).

How can I achieve this programmatically? I've tried the Function approach, but couldn't make it work.

/// handlers/create-database.ts

import { Resource } from "sst";

export const handler = async () => {
  const { Pool } = await import("pg");

  const database = process.env.DATABASE_NAME;
  if (!database) {
    throw new Error("DATABASE_NAME is not set");
  }

  // Connect to the default postgres database to create new databases
  const pool = new Pool({
    host: Resource.AnticaptureDB.host,
    port: Resource.AnticaptureDB.port,
    user: Resource.AnticaptureDB.username,
    password: Resource.AnticaptureDB.password,
    database: "postgres", // Connect to default postgres database
  });

  try {
    // Check if database already exists
    const result = await pool.query(
      "SELECT 1 FROM pg_database WHERE datname = $1",
      [database]
    );

    if (result.rows.length === 0) {
      // Database doesn't exist, create it
      await pool.query(`CREATE DATABASE "${database}"`);
      console.log(`Database ${database} created successfully`);
    } else {
      console.log(`Database ${database} already exists`);
    }
  } catch (error) {
    console.error(`Error creating database ${database}:`, error);
    throw error;
  } finally {
    await pool.end();
  }
};
// functions/create-db.ts

/// <reference path="../../.sst/platform/config.d.ts" />

export function createDb(db: sst.aws.Database, databaseName: string) {
  const func = new sst.aws.Function(`CreateDatabase-${databaseName}`, {
    handler: "src/handlers/create-database.ts",
    link: [db],
    nodejs: {
      install: ["pg"]
    },
    environment: {
      DATABASE_NAME: databaseName,
    },
  })

  return new sst.Linkable(`Database-${databaseName}`, {
    properties: {
      name: databaseName,
      // This ensures the database is created before services that depend on it
      dependsOn: func,
    },
  });
}
AlbertoV5 commented 3 weeks ago

Sorry if it doesn't apply, but would the ci/cd migrations example be relevant here for the function invocation portion? https://sst.dev/docs/examples/#drizzle-migrations-in-cicd

I've been running it to create databases in a single instance and it works ok, by running create db before drizzle migrate.