Skip to content

Database Maintenance

Rack Gateway uses PostgreSQL for persistent storage. This guide covers database maintenance tasks including migrations, backups, and troubleshooting.

The rack-gateway-api binary includes maintenance subcommands for database operations.

Apply pending database migrations:

Terminal window
rack-gateway-api migrate

This command:

  • Connects using DATABASE_URL or PG* environment variables
  • Applies migrations in internal/gateway/db/migrations/
  • Uses schema_migrations table to track applied migrations
  • Is safe to run repeatedly (idempotent)

Reset the database to a clean state (development only):

Terminal window
# Required safety guards
export RESET_RACK_GATEWAY_DATABASE=DELETE_ALL_DATA
export DEV_MODE=true
rack-gateway-api reset-db

Safety guards:

  1. RESET_RACK_GATEWAY_DATABASE=DELETE_ALL_DATA - Must be set exactly
  2. Database must be marked as development, OR set DISABLE_DATABASE_ENVIRONMENT_CHECK=1
  3. For fresh databases, DEV_MODE=true is required

Verify which migrations have been applied:

Terminal window
# Connect to database and check
psql $DATABASE_URL -c "SELECT * FROM schema_migrations ORDER BY version;"

If using AWS RDS, configure automated backups:

# Terraform configuration
resource "aws_db_instance" "gateway" {
# Automated backups
backup_retention_period = 30
backup_window = "03:00-04:00"
# Point-in-time recovery
copy_tags_to_snapshot = true
}

Create a manual backup using pg_dump:

Terminal window
# Full database backup
pg_dump $DATABASE_URL > rack_gateway_backup_$(date +%Y%m%d).sql
# Compressed backup
pg_dump $DATABASE_URL | gzip > rack_gateway_backup_$(date +%Y%m%d).sql.gz
  1. Stop the gateway service

    Terminal window
    convox scale gateway --count 0
  2. Restore the database

    Terminal window
    psql $DATABASE_URL < rack_gateway_backup_20240115.sql
  3. Run any pending migrations

    Terminal window
    rack-gateway-api migrate
  4. Restart the service

    Terminal window
    convox scale gateway --count 2

The database contains these main tables:

TablePurpose
usersUser accounts from OAuth
user_sessionsActive user sessions
api_tokensAPI tokens for CI/CD
mfa_methodsUser MFA enrollments
audit.audit_eventImmutable audit log entries
mfa_backup_codesMFA backup codes
trusted_devicesTrusted devices for step-up
settingsGateway configuration
deploy_approval_requestsPending deploy approvals

Sessions expire automatically, but you can manually clean up:

-- Delete sessions older than 30 days
DELETE FROM user_sessions
WHERE created_at < NOW() - INTERVAL '30 days';

Audit log retention is policy-driven. WORM anchors use AUDIT_ANCHOR_RETENTION_DAYS.

-- Check audit log volume
SELECT COUNT(*), DATE(timestamp) as day
FROM audit.audit_event
GROUP BY DATE(timestamp)
ORDER BY day DESC
LIMIT 10;
-- Manual cleanup (if needed)
DELETE FROM audit.audit_event
WHERE timestamp < NOW() - INTERVAL '400 days';

Regular maintenance improves performance:

-- Analyze query statistics
ANALYZE;
-- Reclaim space from deleted rows
VACUUM ANALYZE;

For RDS, this happens automatically. For self-managed PostgreSQL, schedule regular maintenance.

Configure connection pooling:

Terminal window
DB_MAX_OPEN_CONNS=25 # Maximum concurrent connections
DB_MAX_IDLE_CONNS=5 # Idle connections to keep warm
DB_CONN_MAX_LIFETIME=30m # Connection lifetime
DB_CONN_MAX_IDLE_TIME=10m # Idle timeout
-- Current active connections
SELECT count(*) FROM pg_stat_activity
WHERE datname = 'rack_gateway';
-- Connection details
SELECT usename, application_name, client_addr, state
FROM pg_stat_activity
WHERE datname = 'rack_gateway';

If a migration fails:

  1. Check the error message for the specific issue
  2. Fix the underlying problem (permissions, constraints, etc.)
  3. Re-run rack-gateway migrate

Migrations are transactional—partial failures won’t leave the database in an inconsistent state.

If the gateway can’t connect to the database:

Terminal window
# Test connectivity
psql $DATABASE_URL -c "SELECT 1;"
# Check if host is reachable
nc -zv $PGHOST $PGPORT
# Verify SSL settings
psql "$DATABASE_URL?sslmode=require" -c "SELECT 1;"

Identify slow queries:

-- Enable query logging (if not already)
ALTER SYSTEM SET log_min_duration_statement = '1000'; -- Log queries > 1s
-- Check for long-running queries
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active'
ORDER BY duration DESC;

Check database size:

SELECT pg_size_pretty(pg_database_size('rack_gateway'));
-- Size by table
SELECT relname, pg_size_pretty(pg_total_relation_size(relid))
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC;

When using the Docker development stack:

Terminal window
task docker:db:migrate
Terminal window
task docker:db:reset
Terminal window
docker exec -it rack-gateway-postgres-1 psql -U postgres -d gateway_dev
  1. Always run migrations before starting the app - Include in deployment scripts
  2. Use automated backups - Configure RDS backup retention
  3. Monitor connection usage - Prevent connection exhaustion
  4. Keep audit logs - Don’t delete before retention period expires
  5. Test restore procedures - Verify backups actually work