Environment Lifecycle

Preview Environment Lifecycle #

This guide explains the complete lifecycle of a Preview Environment, from creation to deletion, including automatic management and manual controls.

Lifecycle Stages #

┌───────────────────────────────────────────────────────────────┐
│  Stage 1: Creation                                            │
│  Trigger: 'preview' label added to PR                        │
│  Duration: ~40 minutes                                        │
│  Status: Building → Running → Healthy                        │
└───────────────────────────────────────────────────────────────┘
                           │
                           ▼
┌───────────────────────────────────────────────────────────────┐
│  Stage 2: Active Use                                          │
│  Duration: While PR is open                                   │
│  Status: Running + Healthy                                    │
│  Features: Auto-updates on push, persistent data             │
└───────────────────────────────────────────────────────────────┘
                           │
                           ▼
┌───────────────────────────────────────────────────────────────┐
│  Stage 3: Updates                                             │
│  Trigger: New commits pushed to PR branch                    │
│  Duration: ~10 minutes per update                            │
│  Status: Restarting → Running → Healthy                     │
└───────────────────────────────────────────────────────────────┘
                           │
                           ▼
┌───────────────────────────────────────────────────────────────┐
│  Stage 4: Auto-Stop (optional)                               │
│  Trigger: 30 hours of inactivity                             │
│  Status: Stopped                                             │
│  Note: Can be manually restarted                             │
└───────────────────────────────────────────────────────────────┘
                           │
                           ▼
┌───────────────────────────────────────────────────────────────┐
│  Stage 5: Cleanup                                            │
│  Trigger: PR closed or merged                                │
│  Duration: ~2 minutes                                        │
│  Status: Deleting → Deleted                                 │
└───────────────────────────────────────────────────────────────┘

Automatic Management #

Auto-Creation #

When it happens:

  • When you add the preview label to a PR targeting main

What happens automatically:

  1. GitHub Actions workflow triggered
  2. Coder workspace provisioned
  3. EC2 instance created
  4. System and tools installed
  5. Repository cloned from PR branch
  6. Services built and started
  7. Comment posted to PR with URLs

Timeline:

  • Initial provisioning: 5-10 minutes
  • System setup: 10-15 minutes
  • Application build: 20-25 minutes
  • Service startup: 5 minutes
  • Total: ~40 minutes

Auto-Updates #

When it happens:

  • When you push new commits to the PR branch
  • Only if PR has the preview label

What happens automatically:

  1. GitHub Actions detects new commits
  2. Coder workspace restarted
  3. Latest code pulled from branch
  4. Modified services rebuilt
  5. Services restarted with new code
  6. Comment posted to PR confirming update

Timeline:

  • Pull latest code: 1-2 minutes
  • Rebuild services: 5-7 minutes
  • Service restart: 2-3 minutes
  • Total: ~10 minutes

Data Persistence:

  • ✅ Database data preserved
  • ✅ File uploads preserved
  • ✅ Environment variables preserved
  • ❌ In-memory data cleared
  • ❌ Active sessions ended

Auto-Stop #

When it happens:

  • After 30 hours of workspace inactivity
  • Inactivity = no active SSH sessions, no HTTP requests

What happens automatically:

  1. Workspace transitions to “Stopped” state
  2. All services shut down gracefully
  3. EC2 instance stopped (not terminated)
  4. Data preserved on disk

Cost Savings:

  • Stopped workspaces only pay for storage (~$0.05/hour)
  • Running workspaces cost ~$0.15/hour
  • Can save ~$0.10/hour when stopped

Restarting:

# Via Coder Dashboard
Coder Dashboard → Workspace → Click "Start"

# Services start automatically
# Ready to use in ~2-3 minutes

Auto-Cleanup #

When it happens:

  • Immediately when PR is closed (merged or not)
  • Triggered by GitHub Actions

What happens automatically:

  1. GitHub Actions detects PR closed event
  2. Coder workspace deleted via API
  3. EC2 instance terminated
  4. All data permanently deleted
  5. Comment posted to PR confirming cleanup

Timeline:

  • Workspace deletion: 1-2 minutes
  • Resource cleanup: Immediate
  • Total: ~2 minutes

What gets deleted:

  • ❌ EC2 instance (terminated)
  • ❌ All workspace data
  • ❌ Database data
  • ❌ File uploads
  • ❌ Logs and history
  • ✅ PR comments preserved (in GitHub)

Manual Controls #

Starting a Stopped Workspace #

Via Coder Dashboard:

1. Go to https://coder.internal.gotofu.com/workspaces
2. Find workspace: coder-preview-{PR-number}
3. Click "Start" button
4. Wait 2-3 minutes for services to start

Via Coder CLI:

# Install Coder CLI if needed
brew install coder/coder/coder

# Configure CLI
coder login https://coder.internal.gotofu.com

# Start workspace
coder start coder-preview-{PR-number}

Stopping a Running Workspace #

Why you might want to:

  • Save costs during non-working hours
  • Preserve environment state without deleting
  • Troubleshoot by forcing clean restart

Via Coder Dashboard:

1. Go to workspace page
2. Click "Stop" button
3. Confirm action
4. Wait ~1 minute for graceful shutdown

Via Coder CLI:

coder stop coder-preview-{PR-number}

Note: Stopping is rarely needed as auto-stop handles this automatically.

Restarting a Running Workspace #

Why you might want to:

  • Force rebuild with latest code
  • Clear all in-memory state
  • Recover from service crashes
  • Apply configuration changes

Via Coder Dashboard:

1. Go to workspace page
2. Click "Restart" button
3. Wait ~10 minutes for rebuild

Via Coder CLI:

coder restart coder-preview-{PR-number} --yes

What happens:

  • All services stopped
  • Latest code pulled from branch
  • Modified services rebuilt
  • All services restarted
  • Data preserved on disk

Manual Deletion #

When to use:

  • You want to delete before PR is closed
  • Environment has issues and needs recreation
  • Testing cleanup process

Via Removing Label:

1. Go to PR on GitHub
2. Remove 'preview' label
3. Close PR (if done with it)
4. Workspace automatically deleted

Via Coder Dashboard (Admin only):

1. Go to workspace page
2. Click "Delete" in settings
3. Confirm deletion
4. Workspace permanently deleted

Note: Standard workflow is to let auto-cleanup handle deletion when PR closes.

Data Management #

What Persists Between Updates #

Preserved across restarts:

  • ✅ Database data (PostgreSQL)
  • ✅ File uploads (LocalStack S3)
  • ✅ Redis data
  • ✅ RabbitMQ queues
  • ✅ Git repository state
  • ✅ Environment configuration

Lost on restart:

  • ❌ In-memory cache
  • ❌ Active user sessions
  • ❌ Running background jobs
  • ❌ Temporary files in /tmp
  • ❌ Process state

Backing Up Important Data #

If you have important test data:

# Backup database
docker exec database pg_dump -U postgres bonsai > preview-backup.sql

# Backup files from LocalStack
docker exec bonsai-localstack aws s3 sync s3://assets ./backup-assets --endpoint-url=http://localhost:4566

# Download backups
# Via Coder web terminal or SCP

Note: Backups should be saved outside the workspace if you need them after cleanup.

Restoring Data #

# Restore database
cat preview-backup.sql | docker exec -i database psql -U postgres bonsai

# Restore files to LocalStack
docker exec bonsai-localstack aws s3 sync ./backup-assets s3://assets --endpoint-url=http://localhost:4566

Cleaning Up Test Data #

To start fresh without full rebuild:

# Connect to workspace terminal

# Clear database (but keep schema)
docker exec database psql -U postgres bonsai -c "TRUNCATE TABLE users, organizations, invoices CASCADE;"

# Clear Redis
docker exec bonsai-redis redis-cli FLUSHALL

# Clear RabbitMQ queues
docker exec bonsai-rabbitmq rabbitmqctl purge_queue <queue-name>

# Clear LocalStack S3
docker exec bonsai-localstack aws s3 rm s3://assets --recursive --endpoint-url=http://localhost:4566

Cost Management #

Understanding Costs #

Running Workspace:

  • EC2 t3.2xlarge: ~$0.13/hour
  • EBS storage (500GB): ~$0.02/hour
  • Total: ~$0.15/hour

Stopped Workspace:

  • EC2 stopped: $0.00/hour
  • EBS storage: ~$0.02/hour (still charged)
  • Total: ~$0.02/hour

Monthly estimates:

  • Running 8 hours/day, 5 days/week: ~$24/month
  • Running 24/7: ~$108/month
  • Stopped when not in use: ~$7/month for storage

Best Practices for Cost Savings #

  1. Rely on Auto-Stop

    • Configured for 30 hours of inactivity
    • Automatically stops when not in use
    • No action needed from you
  2. Close PRs When Done

    • Triggers automatic cleanup
    • Deletes all resources
    • Zero cost after deletion
  3. Share Environments

    • Multiple team members can use same preview
    • Avoid creating duplicate environments
    • Coordinate with your team
  4. Manual Stop for Long Breaks

    # Stop workspace before weekend/vacation
    Coder Dashboard → Workspace → Stop
    
    # Restart when you return
    Coder Dashboard → Workspace → Start
    
  5. Delete Unused Previews

    # If you're done testing but PR still open
    # Option 1: Remove 'preview' label
    # Option 2: Close the PR
    

Monitoring Workspace Health #

Via Coder Dashboard #

Go to: https://coder.internal.gotofu.com/workspaces

Health indicators:
- 🟢 Green dot = Healthy + Running
- 🟡 Yellow dot = Starting or Stopping
- 🔴 Red dot = Unhealthy or Failed
- ⚫ Gray dot = Stopped

Build status:
- "Running" = Active and accessible
- "Failed" = Build errors (check logs)
- "Stopped" = Manually stopped or auto-stopped

Via GitHub Actions #

Go to: PR → Actions tab → "Preview Environment" workflow

Status indicators:
- ✅ Green checkmark = Success
- 🟡 Yellow dot = In progress
- ❌ Red X = Failed
- ⚪ Gray = Queued or canceled

Health Check Commands #

# Connect to workspace terminal

# Check all services
docker compose -f docker-compose.preview.yml ps

# Verify critical services are healthy
docker compose -f docker-compose.preview.yml ps | grep -E "(database|rabbitmq|redis|bonsapi|webapp)"

# Check resource usage
docker stats --no-stream

# Check disk space
df -h

# Check memory
free -h

Troubleshooting Lifecycle Issues #

Environment Stuck in “Building” State #

Symptoms:

  • Workspace shows “Building” for >60 minutes
  • No progress in build logs

Solutions:

  1. Check GitHub Actions logs for errors
  2. Check Coder build logs for stuck processes
  3. Cancel build and restart workspace
  4. If persists, delete and recreate

Auto-Update Not Triggering #

Symptoms:

  • Pushed commits but environment doesn’t rebuild
  • Old code still running after 15+ minutes

Check:

  1. PR still has preview label
  2. GitHub Actions workflow triggered
  3. Workspace is running (not stopped)

Solutions:

  1. Manually restart workspace
  2. Remove and re-add preview label
  3. Check GitHub Actions logs for errors

Auto-Stop Happening Too Soon #

Symptoms:

  • Workspace stops while actively using it

Explanation:

  • Auto-stop timer is based on Coder agent activity
  • Sometimes resets unexpectedly

Solution:

  • Simply restart the workspace
  • Activity will reset the timer
  • If it keeps happening, report to DevOps

Cleanup Not Triggering #

Symptoms:

  • PR closed but workspace still exists
  • No cleanup comment posted

Check:

  1. GitHub Actions “cleanup” job status
  2. Check workflow logs for errors

Solutions:

  1. Wait a few minutes (can be delayed)
  2. Manually delete via Coder dashboard
  3. Contact DevOps if workspace cannot be deleted

Lifecycle Best Practices #

For Developers #

  1. Create Early: Add preview label as soon as PR is ready for review
  2. Test Locally First: Verify changes work before creating preview
  3. Monitor Build: Check that initial build succeeds
  4. Update Regularly: Push commits to trigger auto-updates
  5. Close Promptly: Close PR when done to trigger cleanup

For QA Engineers #

  1. Wait for Ready: Don’t start testing until “Ready” comment posted
  2. Document Findings: Add comments to PR with test results
  3. Report Issues: Use GitHub issues or PR comments for bugs
  4. Verify Updates: Re-test after developer pushes fixes
  5. Sign Off: Approve PR or request changes

For Product Managers #

  1. Schedule Reviews: Coordinate timing with developers
  2. Plan Demos: Account for 40-minute initial setup time
  3. Share Feedback: Comment directly on PR
  4. Request Changes: Be specific about what needs adjustment
  5. Approve When Ready: Give explicit approval for merge

FAQ #

Q: Can I have multiple preview environments? #

A: Yes! Each PR gets its own independent environment:

  • PR #123 → coder-preview-123
  • PR #124 → coder-preview-124
  • Both can run simultaneously

Q: What happens to data when I push updates? #

A: Database and files are preserved. Only code is updated.

  • ✅ Database data kept
  • ✅ Uploaded files kept
  • ✅ Configuration kept
  • ❌ In-memory data cleared

Q: Can I manually trigger a rebuild? #

A: Yes, via Coder dashboard:

Workspace page → Restart → Confirm

Q: How long does environment persist? #

A: Until PR is closed:

  • While PR open: Indefinitely (with auto-stop after 30h inactivity)
  • When PR closed: Immediately deleted

Q: Can I prevent auto-stop? #

A: No, but you can easily restart:

  • Auto-stop after 30 hours is by design
  • Restarting takes only 2-3 minutes
  • Data is preserved when stopped

Q: What if I need environment after PR closes? #

A: Options:

  1. Don’t close PR yet
  2. Backup important data before closing
  3. Recreate in staging environment
  4. Create new PR if needed

Q: Can I share workspace with external users? #

A: No, preview environments are internal only:

  • Requires company authentication
  • Internal VPN access needed
  • For external demos, use staging

Next Steps #