Skip to main content

DB Init Lambda

Database initialization Lambda function for creating PostgreSQL databases and users required by Temporal.

Why This Exists

Temporal requires two PostgreSQL databases:

  • temporal - Main storage for workflow state, history, and metadata
  • temporal_visibility - Search and query optimization database

Creating these manually is error-prone and doesn't fit into infrastructure-as-code workflows. The DB Init Lambda:

  • Automates database creation during Terraform deployment
  • Is idempotent - safe to run multiple times
  • Handles permissions - creates user with appropriate grants
  • Runs in VPC - secure access to RDS in private subnets

How It Works

Terraform Deployment


┌───────────────────┐
│ aws_lambda_ │
│ invocation │
│ (db_init) │
└─────────┬─────────┘


┌───────────────────┐ ┌───────────────────┐
│ DB Init Lambda │─────▶│ RDS PostgreSQL │
│ │ │ │
│ 1. Get master │ │ Creates: │
│ creds from SM │ │ - temporal DB │
│ 2. Connect to RDS │ │ - temporal_vis DB │
│ 3. Create DBs │ │ - temporal user │
│ 4. Grant perms │ │ │
└───────────────────┘ └───────────────────┘

Features

FeatureDescription
IdempotentSafe to run multiple times - checks if resources exist
Automatic user creationCreates temporal user with appropriate permissions
Schema permissionsGrants full permissions on public schema
VPC deploymentRuns in private subnets with RDS access
Secrets Manager integrationRetrieves master credentials securely

Environment Variables

VariableDescription
RDS_ENDPOINTRDS instance endpoint (host:port format)
RDS_SECRET_ARNARN of Secrets Manager secret with master credentials
DATABASE_NAMEName of main database to create (default: temporal)
DATABASE_USERName of user to create (default: temporal)

Invocation

Automatic (via Terraform)

The Lambda is invoked automatically during Temporal deployment:

data "aws_lambda_invocation" "db_init" {
function_name = var.db_init_lambda_arn
input = jsonencode({ action = "initialize" })
}

Manual

aws lambda invoke \
--function-name docustack-dev-db-init \
--region us-east-1 \
/tmp/response.json

cat /tmp/response.json

What Gets Created

Databases

DatabasePurpose
temporalMain workflow state, history, metadata
temporal_visibilitySearch and query optimization

User

UserPermissions
temporalFull access to both databases, public schema

Dependencies

The Lambda includes pre-bundled dependencies for Lambda compatibility:

  • psycopg2-binary==2.9.9 - PostgreSQL adapter with native libraries

Deployment

Deployed via the db-init-lambda Terraform module:

module "db_init" {
source = "../../modules/db-init-lambda"

name = "docustack-${var.environment}"
environment = var.environment

vpc_id = module.vpc.vpc_id
private_subnet_ids = module.vpc.private_subnet_ids

rds_endpoint = module.rds.endpoint
rds_secret_arn = module.rds.master_secret_arn

rds_security_group_id = module.rds.security_group_id
}

Development Workflow

Local Testing

Local testing requires network access to RDS, which typically means:

  1. Use a bastion - Connect via SSM port forwarding
  2. Use VPN - If your VPC has VPN access configured
cd docustack-mono/services/lambdas/db-init

# Install dependencies
pip install psycopg2-binary boto3

# Set environment variables
export RDS_ENDPOINT="localhost:5432" # Via port forwarding
export RDS_SECRET_ARN="arn:aws:secretsmanager:..."
export DATABASE_NAME="temporal"
export DATABASE_USER="temporal"

# Test locally
python -c "from handler import lambda_handler; lambda_handler({}, None)"

Testing in AWS

# Invoke the Lambda
aws lambda invoke \
--function-name docustack-dev-db-init \
--region us-east-1 \
/tmp/response.json

cat /tmp/response.json

# Check logs
aws logs tail /aws/lambda/docustack-dev-db-init \
--region us-east-1 \
--since 10m

Troubleshooting

Connection timeout

  1. Verify Lambda is in the same VPC as RDS
  2. Check security group allows Lambda to connect to RDS (port 5432)
  3. Verify Lambda has route to RDS subnet

Permission denied

  1. Check RDS master credentials in Secrets Manager
  2. Verify secret ARN is correct
  3. Check Lambda IAM role has secretsmanager:GetSecretValue permission

Database already exists

This is expected on subsequent runs - the Lambda is idempotent and will skip creation if the database exists.

User already exists

Same as above - the Lambda checks for existing users before creating.

Code Location

docustack-mono/services/lambdas/db-init/
├── handler.py # Main Lambda handler
├── psycopg2/ # Pre-bundled PostgreSQL adapter
└── README.md