Reputation: 8809
I'm using a Lambda via the Script
and Function
constructs to run database migrations against an RDS
instance. However, the Lambda function can't connect to the RDS cluster despite being in the same VPC and subnet according to SST configuration. Here are the relevant parts of the configuration:
function VpcStack({stack, app}: StackContext) {
const vpc = new Vpc(stack, `myapp-${app.stage}-vpc`, {
subnetConfiguration: [
{
name: 'private',
subnetType: SubnetType.PRIVATE_ISOLATED
}
]
})
return {vpc}
}
function DatabaseStack({stack, app}: StackContext) {
dependsOn(VpcStack)
const database = new RDS(stack, 'database', {
engine: 'postgresql13.9',
scaling: {
autoPause: false,
minCapacity: 'ACU_2',
maxCapacity: app.stage === 'production' ? undefined : 'ACU_2'
},
defaultDatabaseName: 'myapp',
cdk: {
cluster: {
clusterIdentifier: `myapp-cluster-${app.stage}`,
vpc: use(VpcStack).vpc,
vpcSubnets: {
subnetType: SubnetType.PRIVATE_ISOLATED
}
}
}
})
return {database}
}
function DatabaseMigrationStack({stack}: StackContext) {
dependsOn(VpcStack)
dependsOn(DatabaseStack)
// Perform database migrations
new Script(stack, 'migrations', {
onUpdate: new Function(stack, 'migrate', {
handler: 'sst/migrations/src/index.migrate',
nodejs: {
format: 'esm',
install: ['pg', 'postgres-migrations'],
minify: false
},
copyFiles: [{from: 'packages/schema/migrations'}],
runtime: 'nodejs18.x',
environment: getDatabaseEnvironment(),
timeout: '5 minutes',
vpc: use(VpcStack).vpc,
vpcSubnets: {
subnetType: SubnetType.PRIVATE_ISOLATED
},
enableLiveDev: false
})
})
}
function getDatabaseEnvironment() {
const {database} = use(DatabaseStack)
return {
DB_HOST: database.clusterEndpoint.hostname,
DB_PORT: database.clusterEndpoint.port.toString(),
DB_NAME: database.defaultDatabaseName,
DB_USER:
database.cdk.cluster.secret
?.secretValueFromJson('username')
.toString() ?? '',
DB_PASS:
database.cdk.cluster.secret
?.secretValueFromJson('password')
.toString() ?? ''
}
}
Here's the migration code before being transpiled to JS:
import path from 'path'
import {migrate as pgmigrate, type MigrateDBConfig} from 'postgres-migrations'
import url from 'url'
declare const process: {
env: {
DB_HOST: string
DB_PORT: string
DB_NAME: string
DB_USER: string
DB_PASS: string
}
}
export async function migrate() {
const dbConfig = {
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT),
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASS,
ensureDatabaseExists: true,
defaultDatabase: 'postgres'
} satisfies MigrateDBConfig
await pgmigrate(
dbConfig,
path.resolve(
path.dirname(url.fileURLToPath(import.meta.url)),
'../../../packages/schema/migrations'
)
)
}
After about 130s I get this error:
{
"errorType": "Error",
"errorMessage": "connect ETIMEDOUT 10.0.142.195:5432",
"trace": [
"Error: connect ETIMEDOUT 10.0.142.195:5432",
" at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1495:16)"
]
}
What would be the reason for this?
Upvotes: 2
Views: 338
Reputation: 8809
I fixed this as follows:
DatabaseStack
, I added the following:
database.cdk.cluster.connections.allowFromAnyIpv4(
Port.tcp(database.clusterEndpoint.port)
)
DatabaseMigrationStack
, I separated out the Function
(called scriptFunction
) and added the following:
const {database} = use(DatabaseStack)
scriptFunction.connections.allowTo(
database.cdk.cluster,
Port.tcp(database.clusterEndpoint.port)
)
Upvotes: 1