|  | 
|  | 1 | +# ServiceLifecycle Lambda with PostgreSQL | 
|  | 2 | + | 
|  | 3 | +This example demonstrates a Swift Lambda function that uses ServiceLifecycle to manage a PostgreSQL connection. The function connects to a publicly accessible RDS PostgreSQL database and queries user data. | 
|  | 4 | + | 
|  | 5 | +## Architecture | 
|  | 6 | + | 
|  | 7 | +- **Swift Lambda Function**: Uses ServiceLifecycle to manage PostgreSQL client lifecycle | 
|  | 8 | +- **PostgreSQL RDS**: Publicly accessible database instance | 
|  | 9 | +- **API Gateway**: HTTP endpoint to invoke the Lambda function | 
|  | 10 | +- **VPC**: Custom VPC with public subnets for RDS and Lambda | 
|  | 11 | + | 
|  | 12 | +## Prerequisites | 
|  | 13 | + | 
|  | 14 | +- Swift 6.x toolchain | 
|  | 15 | +- Docker (for building Lambda functions) | 
|  | 16 | +- AWS CLI configured with appropriate permissions | 
|  | 17 | +- SAM CLI installed | 
|  | 18 | + | 
|  | 19 | +## Database Schema | 
|  | 20 | + | 
|  | 21 | +The Lambda function expects a `users` table with the following structure: | 
|  | 22 | + | 
|  | 23 | +```sql | 
|  | 24 | +CREATE TABLE users ( | 
|  | 25 | +    id SERIAL PRIMARY KEY, | 
|  | 26 | +    username VARCHAR(50) NOT NULL | 
|  | 27 | +); | 
|  | 28 | + | 
|  | 29 | +-- Insert some sample data | 
|  | 30 | +INSERT INTO users (username) VALUES ('alice'), ('bob'), ('charlie'); | 
|  | 31 | +``` | 
|  | 32 | + | 
|  | 33 | +## Deployment | 
|  | 34 | + | 
|  | 35 | +### Option 1: Using the deployment script | 
|  | 36 | + | 
|  | 37 | +```bash | 
|  | 38 | +./deploy.sh | 
|  | 39 | +``` | 
|  | 40 | + | 
|  | 41 | +### Option 2: Manual deployment | 
|  | 42 | + | 
|  | 43 | +1. **Build the Lambda function:** | 
|  | 44 | +   ```bash | 
|  | 45 | +   swift package archive --allow-network-connections docker | 
|  | 46 | +   ``` | 
|  | 47 | + | 
|  | 48 | +2. **Deploy with SAM:** | 
|  | 49 | +   ```bash | 
|  | 50 | +   sam deploy | 
|  | 51 | +   ``` | 
|  | 52 | + | 
|  | 53 | +### Option 3: Deploy with custom parameters | 
|  | 54 | + | 
|  | 55 | +```bash | 
|  | 56 | +sam deploy --parameter-overrides \ | 
|  | 57 | +  DBUsername=myuser \ | 
|  | 58 | +  DBPassword=MySecurePassword123! \ | 
|  | 59 | +  DBName=mydatabase | 
|  | 60 | +``` | 
|  | 61 | + | 
|  | 62 | +## Getting Connection Details | 
|  | 63 | + | 
|  | 64 | +After deployment, get the database connection details: | 
|  | 65 | + | 
|  | 66 | +```bash | 
|  | 67 | +aws cloudformation describe-stacks \ | 
|  | 68 | +  --stack-name servicelifecycle-stack \ | 
|  | 69 | +  --query 'Stacks[0].Outputs' | 
|  | 70 | +``` | 
|  | 71 | + | 
|  | 72 | +The output will include: | 
|  | 73 | +- **DatabaseEndpoint**: Hostname to connect to | 
|  | 74 | +- **DatabasePort**: Port number (5432) | 
|  | 75 | +- **DatabaseName**: Database name | 
|  | 76 | +- **DatabaseUsername**: Username | 
|  | 77 | +- **DatabasePassword**: Password | 
|  | 78 | +- **DatabaseConnectionString**: Complete connection string | 
|  | 79 | + | 
|  | 80 | +## Connecting to the Database | 
|  | 81 | + | 
|  | 82 | +### Using psql | 
|  | 83 | + | 
|  | 84 | +```bash | 
|  | 85 | +# Get the connection details from CloudFormation outputs | 
|  | 86 | +DB_HOST=$(aws cloudformation describe-stacks --stack-name servicelifecycle-stack --query 'Stacks[0].Outputs[?OutputKey==`DatabaseEndpoint`].OutputValue' --output text) | 
|  | 87 | +DB_USER=$(aws cloudformation describe-stacks --stack-name servicelifecycle-stack --query 'Stacks[0].Outputs[?OutputKey==`DatabaseUsername`].OutputValue' --output text) | 
|  | 88 | +DB_NAME=$(aws cloudformation describe-stacks --stack-name servicelifecycle-stack --query 'Stacks[0].Outputs[?OutputKey==`DatabaseName`].OutputValue' --output text) | 
|  | 89 | +DB_PASSWORD=$(aws cloudformation describe-stacks --stack-name servicelifecycle-stack --query 'Stacks[0].Outputs[?OutputKey==`DatabasePassword`].OutputValue' --output text) | 
|  | 90 | + | 
|  | 91 | +# Connect with psql | 
|  | 92 | +psql -h $DB_HOST -U $DB_USER -d $DB_NAME | 
|  | 93 | +``` | 
|  | 94 | + | 
|  | 95 | +### Using connection string | 
|  | 96 | + | 
|  | 97 | +```bash | 
|  | 98 | +# Get the complete connection string | 
|  | 99 | +CONNECTION_STRING=$(aws cloudformation describe-stacks --stack-name servicelifecycle-stack --query 'Stacks[0].Outputs[?OutputKey==`DatabaseConnectionString`].OutputValue' --output text) | 
|  | 100 | + | 
|  | 101 | +# Connect with psql | 
|  | 102 | +psql "$CONNECTION_STRING" | 
|  | 103 | +``` | 
|  | 104 | + | 
|  | 105 | +## Setting up the Database | 
|  | 106 | + | 
|  | 107 | +Once connected to the database, create the required table and sample data: | 
|  | 108 | + | 
|  | 109 | +```sql | 
|  | 110 | +-- Create the users table | 
|  | 111 | +CREATE TABLE users ( | 
|  | 112 | +    id SERIAL PRIMARY KEY, | 
|  | 113 | +    username VARCHAR(50) NOT NULL | 
|  | 114 | +); | 
|  | 115 | + | 
|  | 116 | +-- Insert sample data | 
|  | 117 | +INSERT INTO users (username) VALUES  | 
|  | 118 | +    ('alice'),  | 
|  | 119 | +    ('bob'),  | 
|  | 120 | +    ('charlie'), | 
|  | 121 | +    ('diana'), | 
|  | 122 | +    ('eve'); | 
|  | 123 | +``` | 
|  | 124 | + | 
|  | 125 | +## Testing the Lambda Function | 
|  | 126 | + | 
|  | 127 | +Get the API Gateway endpoint and test the function: | 
|  | 128 | + | 
|  | 129 | +```bash | 
|  | 130 | +# Get the API endpoint | 
|  | 131 | +API_ENDPOINT=$(aws cloudformation describe-stacks --stack-name servicelifecycle-stack --query 'Stacks[0].Outputs[?OutputKey==`APIGatewayEndpoint`].OutputValue' --output text) | 
|  | 132 | + | 
|  | 133 | +# Test the function | 
|  | 134 | +curl "$API_ENDPOINT" | 
|  | 135 | +``` | 
|  | 136 | + | 
|  | 137 | +The function will: | 
|  | 138 | +1. Connect to the PostgreSQL database | 
|  | 139 | +2. Query the `users` table | 
|  | 140 | +3. Log the results | 
|  | 141 | +4. Return "Done" | 
|  | 142 | + | 
|  | 143 | +## Monitoring | 
|  | 144 | + | 
|  | 145 | +Check the Lambda function logs: | 
|  | 146 | + | 
|  | 147 | +```bash | 
|  | 148 | +sam logs -n ServiceLifecycleLambda --stack-name servicelifecycle-stack --tail | 
|  | 149 | +``` | 
|  | 150 | + | 
|  | 151 | +## Security Considerations | 
|  | 152 | + | 
|  | 153 | +⚠️ **Important**: This example creates a publicly accessible PostgreSQL database for demonstration purposes. In production: | 
|  | 154 | + | 
|  | 155 | +1. **Use private subnets** and VPC endpoints | 
|  | 156 | +2. **Implement proper authentication** (IAM database authentication) | 
|  | 157 | +3. **Use AWS Secrets Manager** for password management | 
|  | 158 | +4. **Enable encryption** at rest and in transit | 
|  | 159 | +5. **Configure proper security groups** with minimal required access | 
|  | 160 | +6. **Enable database logging** and monitoring | 
|  | 161 | + | 
|  | 162 | +## Cost Optimization | 
|  | 163 | + | 
|  | 164 | +The template uses: | 
|  | 165 | +- `db.t3.micro` instance (eligible for free tier) | 
|  | 166 | +- Minimal storage allocation (20GB) | 
|  | 167 | +- No Multi-AZ deployment | 
|  | 168 | +- No automated backups | 
|  | 169 | + | 
|  | 170 | +For production workloads, adjust these settings based on your requirements. | 
|  | 171 | + | 
|  | 172 | +## Cleanup | 
|  | 173 | + | 
|  | 174 | +To delete all resources: | 
|  | 175 | + | 
|  | 176 | +```bash | 
|  | 177 | +sam delete --stack-name servicelifecycle-stack | 
|  | 178 | +``` | 
|  | 179 | + | 
|  | 180 | +## Troubleshooting | 
|  | 181 | + | 
|  | 182 | +### Lambda can't connect to database | 
|  | 183 | + | 
|  | 184 | +1. Check security groups allow traffic on port 5432 | 
|  | 185 | +2. Verify the database is publicly accessible | 
|  | 186 | +3. Check VPC configuration and routing | 
|  | 187 | +4. Verify database credentials in environment variables | 
|  | 188 | + | 
|  | 189 | +### Database connection timeout | 
|  | 190 | + | 
|  | 191 | +The PostgreSQL client may hang if the database is unreachable. This is a known issue with PostgresNIO. Ensure: | 
|  | 192 | +1. Database is running and accessible | 
|  | 193 | +2. Security groups are properly configured | 
|  | 194 | +3. Network connectivity is available | 
|  | 195 | + | 
|  | 196 | +### Build failures | 
|  | 197 | + | 
|  | 198 | +Ensure you have: | 
|  | 199 | +1. Swift 6.x toolchain installed | 
|  | 200 | +2. Docker running | 
|  | 201 | +3. Proper network connectivity for downloading dependencies | 
|  | 202 | + | 
|  | 203 | +## Files | 
|  | 204 | + | 
|  | 205 | +- `template.yaml`: SAM template defining all AWS resources | 
|  | 206 | +- `samconfig.toml`: SAM configuration file | 
|  | 207 | +- `deploy.sh`: Deployment script | 
|  | 208 | +- `Sources/Lambda.swift`: Swift Lambda function code | 
|  | 209 | +- `Sources/RootRDSCert.swift`: RDS root certificate for SSL connections | 
|  | 210 | +- `Package.swift`: Swift package definition | 
0 commit comments