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)
