Bỏ qua

Edge Functions Deployment

Deploy Flow

Manual Deployment

# Deploy single function
supabase functions deploy my-function

# Deploy all functions
supabase functions deploy

# Deploy with specific project
supabase functions deploy --project-ref <project-id>

Deployment Process

┌─────────────────────────────────────────────────────────────┐
│                  DEPLOYMENT FLOW                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  1. supabase functions deploy                               │
│     │                                                        │
│     ▼                                                        │
│  2. Bundle TypeScript/JavaScript                            │
│     │                                                        │
│     ▼                                                        │
│  3. Upload to Supabase                                      │
│     │                                                        │
│     ▼                                                        │
│  4. Deploy to global edge network                           │
│     │                                                        │
│     ▼                                                        │
│  5. Function available at:                                   │
│     https://project-ref.supabase.co/functions/v1/name       │
│                                                              │
└─────────────────────────────────────────────────────────────┘

CI/CD Deployment

GitHub Actions

# .github/workflows/deploy-functions.yml
name: Deploy Edge Functions

on:
  push:
    branches: [main]
    paths:
      - 'supabase/functions/**'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Supabase CLI
        uses: supabase/setup-cli@v1
        with:
          version: latest

      - name: Deploy Functions
        run: |
          supabase functions deploy --project-ref ${{ vars.SUPABASE_PROJECT_REF }}
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}

With Secrets Management

name: Deploy Functions with Secrets

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Supabase CLI
        uses: supabase/setup-cli@v1

      - name: Link Project
        run: supabase link --project-ref ${{ vars.SUPABASE_PROJECT_REF }}
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}

      - name: Set Secrets
        run: |
          supabase secrets set \
            STRIPE_SECRET_KEY=${{ secrets.STRIPE_SECRET_KEY }} \
            SENDGRID_API_KEY=${{ secrets.SENDGRID_API_KEY }}
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}

      - name: Deploy Functions
        run: supabase functions deploy
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}

Managing Secrets

Set Secrets

# Set single secret
supabase secrets set MY_API_KEY=sk_live_xxxxx

# Set multiple secrets
supabase secrets set \
  STRIPE_KEY=sk_live_xxx \
  SENDGRID_KEY=SG.xxx \
  WEBHOOK_SECRET=whsec_xxx

# List current secrets (names only, not values)
supabase secrets list

# Unset secret
supabase secrets unset MY_API_KEY

Local Development

# Create local env file
# supabase/functions/.env.local
STRIPE_KEY=sk_test_xxx
SENDGRID_KEY=SG.xxx_test

# Serve with env file
supabase functions serve --env-file supabase/functions/.env.local

Function Versioning

Deployment Strategy

┌─────────────────────────────────────────────────────────────┐
│                  VERSIONING STRATEGY                         │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Option 1: Overwrite (Default)                              │
│  - Each deploy replaces previous version                    │
│  - Simple, no version management                            │
│                                                              │
│  Option 2: Versioned Functions                              │
│  - my-function-v1, my-function-v2                          │
│  - Client specifies version                                 │
│  - More complex, but safer rollbacks                        │
│                                                              │
│  Recommendation: Use Option 1 + Git tags for rollback      │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Rollback Strategy

# Rollback using git
git checkout <previous-commit> -- supabase/functions/my-function/
supabase functions deploy my-function

# Or redeploy from tag
git checkout v1.0.0
supabase functions deploy my-function

Monitoring & Logs

View Logs

# Stream logs
supabase functions logs my-function

# Tail logs
supabase functions logs my-function --follow

# Filter by time
supabase functions logs my-function --since 1h

Dashboard Logs

Supabase Dashboard
└── Edge Functions
    └── Select function
        └── Logs tab
            - Invocations
            - Errors
            - Duration

Error Handling Best Practices

Structured Logging

serve(async (req: Request) => {
  const requestId = crypto.randomUUID();

  console.log(JSON.stringify({
    level: 'info',
    requestId,
    message: 'Function invoked',
    method: req.method,
    url: req.url,
  }));

  try {
    const result = await processRequest(req);

    console.log(JSON.stringify({
      level: 'info',
      requestId,
      message: 'Request processed successfully',
    }));

    return new Response(JSON.stringify(result), {
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (error) {
    console.error(JSON.stringify({
      level: 'error',
      requestId,
      message: 'Request failed',
      error: error.message,
      stack: error.stack,
    }));

    return new Response(
      JSON.stringify({ error: 'Internal server error', requestId }),
      { status: 500, headers: { 'Content-Type': 'application/json' } }
    );
  }
});

Testing Before Deploy

Local Testing

# Start local Supabase
supabase start

# Serve functions locally
supabase functions serve

# Test with curl
curl -X POST http://localhost:54321/functions/v1/my-function \
  -H "Authorization: Bearer $ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "test"}'

Integration Tests

// tests/functions.test.ts
import { createClient } from '@supabase/supabase-js';

describe('Edge Functions', () => {
  const supabase = createClient(
    process.env.SUPABASE_URL!,
    process.env.SUPABASE_ANON_KEY!
  );

  test('my-function returns expected result', async () => {
    const { data, error } = await supabase.functions.invoke('my-function', {
      body: { name: 'test' },
    });

    expect(error).toBeNull();
    expect(data.message).toBe('Hello test!');
  });
});

Tổng kết

Deployment Commands

# Deploy
supabase functions deploy [name]

# Secrets
supabase secrets set KEY=value
supabase secrets list

# Logs
supabase functions logs [name] --follow

CI/CD Checklist

  • [ ] Access token in GitHub secrets
  • [ ] Project ref in GitHub variables
  • [ ] Deploy on push to main
  • [ ] Set function secrets in CI
  • [ ] Monitor logs after deploy

Best Practices

✅ Test locally before deploy
✅ Use environment-specific secrets
✅ Monitor logs after deployment
✅ Tag releases for rollback
✅ Structured logging

Q&A

  1. Có CI/CD pipeline cho functions chưa?
  2. Cần monitoring gì thêm?
  3. Rollback strategy như thế nào?