SiamCafe.net Blog
Technology

Supabase Realtime Progressive Delivery

supabase realtime progressive delivery
Supabase Realtime Progressive Delivery | SiamCafe Blog
2026-05-01· อ. บอม — SiamCafe.net· 1,650 คำ

Supabase Realtime Progressive Delivery คืออะไร

Supabase เป็น open-source Firebase alternative ที่ให้ PostgreSQL database, Authentication, Realtime subscriptions, Storage และ Edge Functions ในแพ็กเกจเดียว Realtime feature ของ Supabase ใช้ PostgreSQL logical replication เพื่อ broadcast database changes ให้ clients แบบ real-time Progressive Delivery คือแนวทาง deploy software แบบค่อยๆ ปล่อยให้ผู้ใช้กลุ่มเล็กก่อน แล้วขยายไปยังทุกู้คืน เช่น feature flags, canary releases, blue-green deployments การรวม Supabase Realtime กับ Progressive Delivery ช่วยให้ปล่อย features ใหม่อย่างปลอดภัย พร้อมติดตาม real-time feedback

Supabase Realtime Architecture

# supabase_realtime.py — Supabase Realtime architecture
import json

class SupabaseRealtime:
    FEATURES = {
        "postgres_changes": {
            "name": "Postgres Changes",
            "description": "Listen to INSERT, UPDATE, DELETE events จาก PostgreSQL tables",
            "use_case": "Real-time dashboard, live feeds, notifications",
        },
        "broadcast": {
            "name": "Broadcast",
            "description": "ส่ง messages ระหว่าง clients ผ่าน channels — ไม่ผ่าน DB",
            "use_case": "Chat, cursor tracking, live collaboration",
        },
        "presence": {
            "name": "Presence",
            "description": "Track online status ของ users ใน channel",
            "use_case": "Online indicators, typing indicators, active users",
        },
    }

    CLIENT_CODE = """
// JavaScript — Supabase Realtime subscription
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)

// 1. Listen to Postgres Changes
const channel = supabase
  .channel('db-changes')
  .on('postgres_changes',
    { event: '*', schema: 'public', table: 'features' },
    (payload) => {
      console.log('Change:', payload.eventType, payload.new)
      // Update UI based on feature flag change
      if (payload.new.enabled) {
        enableFeature(payload.new.name)
      } else {
        disableFeature(payload.new.name)
      }
    }
  )
  .subscribe()

// 2. Broadcast — send events to other clients
const broadcastChannel = supabase.channel('deployments')
broadcastChannel.on('broadcast', { event: 'deploy_status' }, (payload) => {
  console.log('Deploy:', payload.payload)
  updateDeployStatus(payload.payload)
})
broadcastChannel.subscribe()

// Send deployment event
broadcastChannel.send({
  type: 'broadcast',
  event: 'deploy_status',
  payload: { version: '2.1.0', status: 'canary', progress: 25 }
})

// 3. Presence — track online users
const presenceChannel = supabase.channel('online')
presenceChannel.on('presence', { event: 'sync' }, () => {
  const state = presenceChannel.presenceState()
  console.log('Online users:', Object.keys(state).length)
})
presenceChannel.subscribe(async (status) => {
  if (status === 'SUBSCRIBED') {
    await presenceChannel.track({ user_id: 'user123', role: 'developer' })
  }
})
"""

    def show_features(self):
        print("=== Supabase Realtime Features ===\n")
        for key, feat in self.FEATURES.items():
            print(f"[{feat['name']}]")
            print(f"  {feat['description']}")
            print(f"  Use: {feat['use_case']}")
            print()

    def show_client(self):
        print("=== Client Code ===")
        print(self.CLIENT_CODE[:500])

rt = SupabaseRealtime()
rt.show_features()
rt.show_client()

Progressive Delivery Patterns

# progressive.py — Progressive delivery patterns
import json

class ProgressiveDelivery:
    PATTERNS = {
        "feature_flags": {
            "name": "Feature Flags",
            "description": "เปิด/ปิด features ผ่าน configuration — ไม่ต้อง redeploy",
            "supabase": "เก็บ flags ใน Supabase table → Realtime broadcast เมื่อเปลี่ยน",
        },
        "canary": {
            "name": "Canary Release",
            "description": "ปล่อยให้ 5-10% ของ traffic ใช้ version ใหม่ก่อน",
            "supabase": "Track canary metrics real-time → rollback ถ้า error rate สูง",
        },
        "blue_green": {
            "name": "Blue-Green Deployment",
            "description": "มี 2 environments — สลับ traffic ระหว่าง blue/green",
            "supabase": "Realtime notify ว่ากำลัง switch → monitor health",
        },
        "percentage_rollout": {
            "name": "Percentage Rollout",
            "description": "เพิ่ม % ผู้ใช้ทีละขั้น: 1% → 5% → 25% → 50% → 100%",
            "supabase": "Update percentage ใน DB → Realtime push ไปทุก client",
        },
        "ring_deployment": {
            "name": "Ring Deployment",
            "description": "Deploy ทีละ ring: internal → beta → early adopters → all",
            "supabase": "Track ring status real-time → auto-promote ถ้า metrics ดี",
        },
    }

    SCHEMA = """
-- Supabase schema for progressive delivery
CREATE TABLE features (
    id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    description TEXT,
    enabled BOOLEAN DEFAULT false,
    rollout_percentage INT DEFAULT 0 CHECK (rollout_percentage BETWEEN 0 AND 100),
    target_rings TEXT[] DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT now(),
    updated_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE feature_assignments (
    id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
    feature_id UUID REFERENCES features(id),
    user_id UUID NOT NULL,
    variant TEXT DEFAULT 'control',
    assigned_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE deployment_events (
    id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
    feature_name TEXT NOT NULL,
    event_type TEXT NOT NULL, -- 'rollout', 'rollback', 'promote', 'pause'
    old_percentage INT,
    new_percentage INT,
    reason TEXT,
    created_at TIMESTAMPTZ DEFAULT now()
);

-- Enable Realtime
ALTER PUBLICATION supabase_realtime ADD TABLE features;
ALTER PUBLICATION supabase_realtime ADD TABLE deployment_events;
"""

    def show_patterns(self):
        print("=== Progressive Delivery Patterns ===\n")
        for key, p in self.PATTERNS.items():
            print(f"[{p['name']}]")
            print(f"  {p['description']}")
            print(f"  Supabase: {p['supabase']}")
            print()

    def show_schema(self):
        print("=== Database Schema ===")
        print(self.SCHEMA[:400])

pd = ProgressiveDelivery()
pd.show_patterns()
pd.show_schema()

Python Feature Flag Manager

# feature_flags.py — Python feature flag manager with Supabase
import json

class FeatureFlagManager:
    CODE = """
# feature_manager.py — Manage feature flags via Supabase
import os
import json
import hashlib
from supabase import create_client

class FeatureFlagManager:
    def __init__(self):
        url = os.environ.get('SUPABASE_URL')
        key = os.environ.get('SUPABASE_KEY')
        self.client = create_client(url, key)
    
    def create_flag(self, name, description='', rollout_pct=0):
        '''Create a new feature flag'''
        result = self.client.table('features').insert({
            'name': name,
            'description': description,
            'enabled': rollout_pct > 0,
            'rollout_percentage': rollout_pct,
        }).execute()
        return result.data[0] if result.data else None
    
    def is_enabled(self, feature_name, user_id=None):
        '''Check if feature is enabled for user'''
        result = self.client.table('features')\\
            .select('*')\\
            .eq('name', feature_name)\\
            .single()\\
            .execute()
        
        feature = result.data
        if not feature or not feature['enabled']:
            return False
        
        if feature['rollout_percentage'] >= 100:
            return True
        
        if user_id:
            # Deterministic assignment based on user_id + feature_name
            hash_input = f"{user_id}:{feature_name}"
            hash_value = int(hashlib.md5(hash_input.encode()).hexdigest(), 16)
            bucket = hash_value % 100
            return bucket < feature['rollout_percentage']
        
        return False
    
    def rollout(self, feature_name, percentage):
        '''Update rollout percentage'''
        # Get current state
        current = self.client.table('features')\\
            .select('rollout_percentage')\\
            .eq('name', feature_name)\\
            .single()\\
            .execute()
        
        old_pct = current.data['rollout_percentage'] if current.data else 0
        
        # Update feature
        self.client.table('features').update({
            'rollout_percentage': percentage,
            'enabled': percentage > 0,
            'updated_at': 'now()',
        }).eq('name', feature_name).execute()
        
        # Log event
        self.client.table('deployment_events').insert({
            'feature_name': feature_name,
            'event_type': 'rollout',
            'old_percentage': old_pct,
            'new_percentage': percentage,
        }).execute()
        
        return {'feature': feature_name, 'percentage': percentage}
    
    def rollback(self, feature_name, reason=''):
        '''Rollback feature to 0%'''
        return self.rollout(feature_name, 0)
    
    def progressive_rollout(self, feature_name, stages=None):
        '''Define progressive rollout stages'''
        if stages is None:
            stages = [1, 5, 25, 50, 100]
        
        return {
            'feature': feature_name,
            'stages': stages,
            'current_stage': 0,
            'note': 'Call rollout() with each stage percentage after validation',
        }
    
    def list_flags(self):
        '''List all feature flags'''
        result = self.client.table('features')\\
            .select('*')\\
            .order('created_at', desc=True)\\
            .execute()
        return result.data

# mgr = FeatureFlagManager()
# mgr.create_flag('new-checkout', 'New checkout flow', rollout_pct=5)
# enabled = mgr.is_enabled('new-checkout', user_id='user123')
# mgr.rollout('new-checkout', 25)  # Increase to 25%
"""

    def show_code(self):
        print("=== Feature Flag Manager ===")
        print(self.CODE[:600])

mgr = FeatureFlagManager()
mgr.show_code()

Monitoring Dashboard

# dashboard.py — Real-time monitoring for progressive delivery
import json
import random

class DeliveryDashboard:
    METRICS = {
        "error_rate": "Error rate ของ feature ใหม่ vs baseline — ต้องไม่สูงกว่า 1.5x",
        "latency_p95": "P95 latency — ต้องไม่สูงกว่า baseline + 20%",
        "conversion": "Conversion rate — ต้องไม่ต่ำกว่า baseline - 5%",
        "crash_rate": "App crash rate — ต้องไม่สูงกว่า baseline + 0.1%",
        "user_feedback": "User feedback/complaints — monitor via support tickets",
    }

    AUTOMATION = {
        "auto_promote": {
            "name": "Auto-Promote",
            "description": "ถ้า metrics ดี > 24 ชั่วโมง → เพิ่ม rollout % อัตโนมัติ",
            "stages": "1% → 5% → 25% → 50% → 100% (24h ต่อ stage)",
        },
        "auto_rollback": {
            "name": "Auto-Rollback",
            "description": "ถ้า error rate > threshold → rollback อัตโนมัติ",
            "trigger": "error_rate > 2x baseline OR p95_latency > 3x baseline",
        },
        "alerting": {
            "name": "Real-time Alerting",
            "description": "Supabase Realtime → ส่ง alert ผ่าน Slack/PagerDuty",
            "channels": "Slack #deployments, PagerDuty for critical",
        },
    }

    def show_metrics(self):
        print("=== Monitoring Metrics ===\n")
        for metric, desc in self.METRICS.items():
            print(f"  [{metric}] {desc}")

    def show_automation(self):
        print(f"\n=== Automation ===")
        for key, auto in self.AUTOMATION.items():
            print(f"\n[{auto['name']}]")
            print(f"  {auto['description']}")

    def sample_dashboard(self):
        print(f"\n=== Live Dashboard ===")
        features = [
            ("new-checkout", 25, "canary"),
            ("dark-mode", 100, "ga"),
            ("ai-search", 5, "canary"),
        ]
        for name, pct, status in features:
            error = round(random.uniform(0.1, 2.0), 2)
            print(f"  [{name}] {pct}% ({status}) | error: {error}% | latency: {random.randint(50, 300)}ms")

dashboard = DeliveryDashboard()
dashboard.show_metrics()
dashboard.show_automation()
dashboard.sample_dashboard()

Edge Functions Integration

# edge.py — Supabase Edge Functions for progressive delivery
import json

class EdgeFunctions:
    FUNCTION_CODE = """
// supabase/functions/check-feature/index.ts
// Supabase Edge Function — Check feature flag
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'

serve(async (req) => {
  const { feature_name, user_id } = await req.json()
  
  const supabase = createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
  )
  
  const { data: feature } = await supabase
    .from('features')
    .select('*')
    .eq('name', feature_name)
    .single()
  
  if (!feature || !feature.enabled) {
    return new Response(JSON.stringify({ enabled: false }))
  }
  
  // Deterministic hash-based assignment
  const encoder = new TextEncoder()
  const data = encoder.encode(`:`)
  const hashBuffer = await crypto.subtle.digest('SHA-256', data)
  const hashArray = new Uint8Array(hashBuffer)
  const bucket = hashArray[0] % 100
  
  const enabled = bucket < feature.rollout_percentage
  
  return new Response(JSON.stringify({
    enabled,
    feature: feature_name,
    rollout_percentage: feature.rollout_percentage,
    variant: enabled ? 'treatment' : 'control',
  }))
})
"""

    def show_function(self):
        print("=== Edge Function ===")
        print(self.FUNCTION_CODE[:500])

edge = EdgeFunctions()
edge.show_function()

FAQ - คำถามที่พบบ่อย

Q: Supabase Realtime ดีกว่า Firebase Realtime Database ไหม?

A: Supabase: PostgreSQL (SQL, relational), open-source, self-host ได้, Realtime ผ่าน logical replication Firebase: NoSQL (document), proprietary, Google Cloud only ข้อดี Supabase: SQL queries, joins, migrations, full Postgres ecosystem ข้อดี Firebase: Offline support ดีกว่า, SDK mature กว่า, integration กับ Google services เลือก Supabase: ถ้าต้องการ relational DB + open-source + self-host option

Q: Progressive Delivery ต่างจาก CI/CD อย่างไร?

A: CI/CD: build + test + deploy อัตโนมัติ — focus ที่ speed of delivery Progressive Delivery: ควบคุมว่าใครเห็น feature ใหม่ — focus ที่ safety CI/CD เป็น subset: deploy code → แต่ Progressive Delivery ควบคุมว่า code ทำงานกับใคร ใช้ร่วมกัน: CI/CD deploy code + feature flags ควบคุม rollout

Q: Feature flags เพิ่ม technical debt ไหม?

A: ได้ — ถ้าไม่จัดการ: flags เก่าที่ rollout 100% แล้วแต่ไม่ลบ code = debt วิธีจัดการ: กำหนด expiry date สำหรับทุก flag, review ทุก sprint, ลบ flags ที่ 100% แล้ว > 30 วัน ข้อดี > debt: reduce risk, faster feedback, ability to rollback สำคัญ: มี process cleanup flags — ไม่ปล่อยให้สะสม

Q: Supabase Realtime รองรับกี่ concurrent connections?

A: Free tier: 200 concurrent connections Pro tier: 500 concurrent connections (เพิ่มได้) Self-hosted: ไม่จำกัด (ตาม server capacity) ถ้าต้องการมากกว่า: ใช้ Supabase Realtime multiplexer หรือ self-host สำหรับ production: Pro tier พอสำหรับ app ส่วนใหญ่ (500 connections = 500 active users)

📖 บทความที่เกี่ยวข้อง

Supabase Realtime Monitoring และ Alertingอ่านบทความ → Supabase Realtime Tech Conference 2026อ่านบทความ → Supabase Realtime Hexagonal Architectureอ่านบทความ → Supabase Realtime Multi-cloud Strategyอ่านบทความ → Supabase Realtime Open Source Contributionอ่านบทความ →

📚 ดูบทความทั้งหมด →