Supabase Realtime Observability Stack คืออะไร
Supabase เป็น open source Firebase alternative ที่ให้บริการ PostgreSQL database, authentication, real-time subscriptions, storage และ edge functions Realtime คือ feature ที่ช่วยให้ clients รับ database changes แบบ real-time ผ่าน WebSocket Observability Stack คือชุดเครื่องมือสำหรับ monitor, trace และ debug ระบบ การรวมแนวคิดเหล่านี้ช่วยสร้าง real-time applications ที่มี observability ครบถ้วน ติดตาม performance, errors และ user behavior ได้แบบ real-time
Supabase Architecture
# supabase_arch.py — Supabase platform architecture
import json
class SupabaseArch:
SERVICES = {
"postgres": {
"name": "PostgreSQL Database",
"description": "Core database — full PostgreSQL with extensions (pgvector, PostGIS)",
"port": 5432,
},
"realtime": {
"name": "Realtime Server",
"description": "WebSocket server ที่ broadcast database changes ให้ clients",
"protocol": "WebSocket (Phoenix Channels)",
},
"auth": {
"name": "GoTrue (Auth)",
"description": "Authentication server — email, OAuth, magic links, MFA",
"providers": "Google, GitHub, Apple, Discord, etc.",
},
"storage": {
"name": "Storage",
"description": "S3-compatible object storage สำหรับ files, images",
"features": "Policies, transformations, CDN",
},
"edge_functions": {
"name": "Edge Functions",
"description": "Serverless functions (Deno runtime) deploy globally",
"use": "Custom logic, webhooks, integrations",
},
"postgrest": {
"name": "PostgREST",
"description": "Auto-generate REST API จาก PostgreSQL schema",
"feature": "Instant CRUD API, filtering, pagination",
},
}
REALTIME_FEATURES = {
"postgres_changes": {
"name": "Postgres Changes",
"description": "Subscribe to INSERT, UPDATE, DELETE events บน tables",
"example": "Real-time chat, live dashboards, notifications",
},
"broadcast": {
"name": "Broadcast",
"description": "Send messages ระหว่าง clients ผ่าน channels",
"example": "Cursor tracking, typing indicators, multiplayer",
},
"presence": {
"name": "Presence",
"description": "Track online users และ shared state",
"example": "Online indicators, collaborative editing",
},
}
def show_services(self):
print("=== Supabase Services ===\n")
for key, svc in self.SERVICES.items():
print(f"[{svc['name']}]")
print(f" {svc['description']}")
print()
def show_realtime(self):
print("=== Realtime Features ===")
for key, feature in self.REALTIME_FEATURES.items():
print(f" [{feature['name']}] {feature['description']}")
print(f" Example: {feature['example']}")
arch = SupabaseArch()
arch.show_services()
arch.show_realtime()
Realtime Implementation
# realtime.py — Supabase Realtime implementation
import json
class RealtimeImplementation:
JS_CLIENT = """
// supabase-realtime.js — Client-side realtime subscription
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://your-project.supabase.co',
'your-anon-key'
)
// 1. Subscribe to database changes
const channel = supabase
.channel('db-changes')
.on('postgres_changes',
{ event: '*', schema: 'public', table: 'messages' },
(payload) => {
console.log('Change:', payload.eventType, payload.new)
if (payload.eventType === 'INSERT') {
addMessage(payload.new)
} else if (payload.eventType === 'UPDATE') {
updateMessage(payload.new)
} else if (payload.eventType === 'DELETE') {
removeMessage(payload.old)
}
}
)
.subscribe()
// 2. Broadcast (client-to-client)
const broadcastChannel = supabase.channel('room-1')
broadcastChannel
.on('broadcast', { event: 'cursor' }, (payload) => {
updateCursor(payload.payload)
})
.subscribe()
// Send cursor position
broadcastChannel.send({
type: 'broadcast',
event: 'cursor',
payload: { x: 100, y: 200, user: 'alice' }
})
// 3. Presence (online users)
const presenceChannel = supabase.channel('online-users')
presenceChannel
.on('presence', { event: 'sync' }, () => {
const state = presenceChannel.presenceState()
console.log('Online:', Object.keys(state).length)
})
.subscribe(async (status) => {
if (status === 'SUBSCRIBED') {
await presenceChannel.track({ user: 'alice', online_at: new Date() })
}
})
"""
PYTHON_CLIENT = """
# supabase_realtime.py — Python backend integration
from supabase import create_client
import os
SUPABASE_URL = os.getenv("SUPABASE_URL")
SUPABASE_KEY = os.getenv("SUPABASE_SERVICE_KEY")
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
# Insert data (triggers realtime for subscribers)
def send_message(room_id, user_id, content):
result = supabase.table("messages").insert({
"room_id": room_id,
"user_id": user_id,
"content": content,
}).execute()
return result.data
# Query with filters
def get_messages(room_id, limit=50):
result = supabase.table("messages") \\
.select("*, users(name, avatar)") \\
.eq("room_id", room_id) \\
.order("created_at", desc=True) \\
.limit(limit) \\
.execute()
return result.data
# Enable Row Level Security (RLS)
# CREATE POLICY "users can read own room messages"
# ON messages FOR SELECT
# USING (room_id IN (SELECT room_id FROM room_members WHERE user_id = auth.uid()))
"""
def show_js(self):
print("=== JavaScript Client ===")
print(self.JS_CLIENT[:600])
def show_python(self):
print(f"\n=== Python Backend ===")
print(self.PYTHON_CLIENT[:500])
rt = RealtimeImplementation()
rt.show_js()
rt.show_python()
Observability Stack
# observability.py — Observability stack for Supabase
import json
import random
class ObservabilityStack:
PILLARS = {
"metrics": {
"name": "Metrics",
"tools": ["Prometheus", "Grafana", "Supabase Dashboard"],
"what": "CPU, memory, connections, queries/sec, realtime subscribers",
},
"logs": {
"name": "Logs",
"tools": ["Supabase Logs (built-in)", "Logflare", "Loki"],
"what": "API logs, auth logs, realtime logs, edge function logs",
},
"traces": {
"name": "Traces",
"tools": ["OpenTelemetry", "Jaeger", "Sentry"],
"what": "Request traces, database query traces, function execution",
},
}
SUPABASE_METRICS = """
# supabase_monitor.py — Monitor Supabase metrics
import requests
import json
class SupabaseMonitor:
def __init__(self, project_ref, service_key):
self.base_url = f"https://{project_ref}.supabase.co"
self.headers = {
"apikey": service_key,
"Authorization": f"Bearer {service_key}",
}
def health_check(self):
endpoints = {
"rest": f"{self.base_url}/rest/v1/",
"auth": f"{self.base_url}/auth/v1/health",
"realtime": f"{self.base_url}/realtime/v1/",
"storage": f"{self.base_url}/storage/v1/",
}
results = {}
for name, url in endpoints.items():
try:
resp = requests.get(url, headers=self.headers, timeout=5)
results[name] = {"status": resp.status_code, "healthy": resp.status_code < 400}
except Exception as e:
results[name] = {"status": "error", "healthy": False, "error": str(e)}
return results
def db_metrics(self):
query = '''
SELECT
count(*) as total_connections,
count(*) FILTER (WHERE state = 'active') as active,
count(*) FILTER (WHERE state = 'idle') as idle
FROM pg_stat_activity
'''
resp = requests.post(
f"{self.base_url}/rest/v1/rpc/exec_sql",
headers=self.headers,
json={"query": query}
)
return resp.json()
monitor = SupabaseMonitor("your-project", "your-service-key")
health = monitor.health_check()
for svc, status in health.items():
print(f" [{svc}] {'OK' if status['healthy'] else 'FAIL'} ({status['status']})")
"""
def show_pillars(self):
print("=== Observability Pillars ===\n")
for key, pillar in self.PILLARS.items():
print(f"[{pillar['name']}]")
print(f" Tools: {', '.join(pillar['tools'])}")
print(f" What: {pillar['what']}")
print()
def show_monitor(self):
print("=== Supabase Monitor ===")
print(self.SUPABASE_METRICS[:500])
def dashboard(self):
print(f"\n=== Live Dashboard ===")
metrics = {
"DB Connections": f"{random.randint(10, 50)}/100",
"Realtime Subscribers": random.randint(50, 500),
"API Requests/min": random.randint(100, 5000),
"Auth Sessions": random.randint(200, 2000),
"Storage Usage": f"{random.randint(1, 50)} GB",
"Edge Function Invocations": f"{random.randint(100, 10000)}/day",
"P95 Latency": f"{random.randint(20, 200)}ms",
}
for m, v in metrics.items():
print(f" {m}: {v}")
obs = ObservabilityStack()
obs.show_pillars()
obs.show_monitor()
obs.dashboard()
Alerting & Error Tracking
# alerting.py — Alerting and error tracking
import json
import random
class AlertingSetup:
SENTRY_INTEGRATION = """
// sentry-supabase.js — Sentry integration
import * as Sentry from '@sentry/browser'
import { createClient } from '@supabase/supabase-js'
Sentry.init({
dsn: 'https://xxx@sentry.io/yyy',
tracesSampleRate: 0.1,
integrations: [Sentry.browserTracingIntegration()],
})
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
// Wrap Supabase calls with error tracking
async function fetchData(table, filters = {}) {
const span = Sentry.startSpan({ name: `supabase.` })
try {
let query = supabase.from(table).select('*')
for (const [key, value] of Object.entries(filters)) {
query = query.eq(key, value)
}
const { data, error } = await query
if (error) {
Sentry.captureException(new Error(`Supabase error: `))
throw error
}
return data
} finally {
span?.end()
}
}
"""
def show_sentry(self):
print("=== Sentry Integration ===")
print(self.SENTRY_INTEGRATION[:500])
def alert_rules(self):
print(f"\n=== Alert Rules ===")
rules = [
{"condition": "DB connections > 80%", "action": "Slack warning", "priority": "P2"},
{"condition": "API error rate > 5%", "action": "PagerDuty alert", "priority": "P1"},
{"condition": "Realtime disconnections spike", "action": "Slack + investigate", "priority": "P2"},
{"condition": "Auth failures > 50/min", "action": "Block IP + alert", "priority": "P1"},
{"condition": "Edge function timeout > 10s", "action": "Slack warning", "priority": "P3"},
{"condition": "Storage > 90% capacity", "action": "Email notification", "priority": "P2"},
]
for r in rules:
print(f" [{r['priority']}] {r['condition']} → {r['action']}")
def incident_simulation(self):
print(f"\n=== Recent Incidents ===")
incidents = [
{"time": "2h ago", "type": "Realtime", "desc": f"WebSocket reconnections spike ({random.randint(50, 200)} disconnections)", "status": "Resolved"},
{"time": "1d ago", "type": "Database", "desc": f"Slow query ({random.randint(5, 30)}s) blocking connections", "status": "Resolved"},
{"time": "3d ago", "type": "Auth", "desc": f"Brute force attempt ({random.randint(100, 500)} attempts)", "status": "Mitigated"},
]
for i in incidents:
print(f" [{i['status']:>8}] {i['time']:>5} [{i['type']}] {i['desc']}")
alert = AlertingSetup()
alert.show_sentry()
alert.alert_rules()
alert.incident_simulation()
Performance Optimization
# performance.py — Supabase performance optimization
import json
class PerformanceOptimization:
TIPS = {
"database": {
"name": "Database Optimization",
"tips": [
"สร้าง indexes สำหรับ columns ที่ query บ่อย",
"ใช้ connection pooling (PgBouncer built-in)",
"Enable RLS แต่เขียน policies ให้ efficient",
"ใช้ materialized views สำหรับ complex aggregations",
"VACUUM ANALYZE เป็นประจำ (auto-vacuum enabled by default)",
],
},
"realtime": {
"name": "Realtime Optimization",
"tips": [
"Subscribe เฉพาะ tables/columns ที่จำเป็น",
"ใช้ filters ใน subscription (eq, in, gte)",
"Unsubscribe เมื่อ component unmount",
"Rate limit broadcast messages",
"ใช้ Presence เฉพาะ features ที่ต้องการจริง",
],
},
"api": {
"name": "API Optimization",
"tips": [
"ใช้ select() เฉพาะ columns ที่ต้องการ",
"Pagination: range() แทน limit+offset สำหรับ large datasets",
"Batch operations สำหรับ multiple inserts",
"Cache responses ด้วย SWR/React Query",
"ใช้ Edge Functions สำหรับ complex logic",
],
},
}
def show_tips(self):
print("=== Performance Tips ===\n")
for key, category in self.TIPS.items():
print(f"[{category['name']}]")
for tip in category["tips"][:3]:
print(f" • {tip}")
print()
def benchmark(self):
import random
print("=== Performance Benchmark ===")
benchmarks = {
"REST API (simple select)": f"{random.randint(5, 30)}ms",
"REST API (join query)": f"{random.randint(20, 100)}ms",
"Realtime latency": f"{random.randint(10, 50)}ms",
"Auth (sign in)": f"{random.randint(50, 200)}ms",
"Storage (upload 1MB)": f"{random.randint(100, 500)}ms",
"Edge Function (cold start)": f"{random.randint(50, 300)}ms",
}
for name, latency in benchmarks.items():
print(f" {name}: {latency}")
perf = PerformanceOptimization()
perf.show_tips()
perf.benchmark()
FAQ - คำถามที่พบบ่อย
Q: Supabase กับ Firebase อันไหนดี?
A: Supabase: PostgreSQL (relational), open source, self-host ได้, SQL Firebase: NoSQL (Firestore), Google ecosystem, mature, serverless ใช้ Supabase: relational data, SQL preference, open source, migrate ง่าย ใช้ Firebase: NoSQL fits, Google Cloud integration, mobile-first
Q: Realtime มี limits ไหม?
A: Free plan: 200 concurrent connections, 2M realtime messages/month Pro plan: 500 connections, 5M messages, increase ได้ Self-hosted: ไม่มี limit (ขึ้นกับ server resources) Tips: unsubscribe เมื่อไม่ใช้, filter subscriptions ให้แคบ
Q: Supabase self-host ยากไหม?
A: ใช้ Docker Compose: ง่ายสำหรับ development Production self-host: ต้อง manage PostgreSQL, Kong, GoTrue, Realtime แยก แนะนำ: ใช้ hosted service สำหรับ production (ลด ops burden) Self-host เหมาะ: compliance requirements, data sovereignty, cost optimization
Q: Observability ต้องใช้ tools อะไรบ้าง?
A: เริ่มต้น: Supabase Dashboard (built-in logs + metrics) เพิ่ม: Sentry (error tracking), Grafana (dashboards) Advanced: OpenTelemetry (traces), Loki (logs), Prometheus (metrics) สำคัญที่สุด: monitor DB connections, API error rate, realtime subscriber count
