Bauen Sie eine echte Echtzeit-Bietungsmaschine mit Supabase Realtime
Ihr erstes Bietungssystem hat die Datenbank jede Sekunde abgefragt. Gebote kamen in der falschen Reihenfolge an. Einige verschwanden komplett. Sie haben eine separate WebSocket-Server für die zweite Version hinzugefügt – besser, aber jetzt verwalten Sie zwei Infrastrukturen. Der dritte Versuch verwendete Supabase Realtime, und die Race Conditions hörten auf. Kein Polling-Loop. Kein eigenständiger Socket-Server. PostgreSQL-Trigger senden Bid-Updates aus, sobald sie committed werden, und jeder verbundene Client sieht denselben Status innerhalb von 50 Millisekunden. Ich habe in zwei Jahren drei Auktionssysteme bereitgestellt. Die Supabase-Version ist die einzige, die ich nach dem Start nicht neu aufbauen musste. Hier ist die Architektur, die es funktioniert hat – und die eine Funktion, die sie fast zum Scheitern gebracht hätte.
Supabase Realtime sitzt auf PostgreSQL's Write-Ahead Log (WAL) auf und nutzt einen Elixir-basierten Server, um Datenbankänderungen über WebSockets an verbundene Clients zu pushen. Für ein Auktionssystem bedeutet dies, dass jedes Gebot, das Ihre Datenbank erreicht, sofort an jeden Bieter propagiert wird, der diese Auktion beobachtet. Kein Polling. Keine separate Pub/Sub-Infrastruktur. Ihre Datenbank ist Ihr Event-System.
Lassen Sie uns von Grund auf eine bauen.
Inhaltsverzeichnis
- Architekturüberblick
- Datenbankschema und Setup
- PostgreSQL-Trigger für Bid-Logik
- Client-seitige Abonnements mit JavaScript
- Race Conditions und Bid-Validierung handhaben
- Presence Tracking für aktive Bieter
- Performance-Tuning und Produktionsüberlegungen
- Supabase Realtime vs. Alternativen
- Bereitstellung und Skalierung Ihres Auktionssystems
- Häufig gestellte Fragen
Architekturüberblick
Bevor Sie Code schreiben, verstehen Sie, was Sie bauen und wie die Teile zusammenpassen.
Supabase Realtime bietet Ihnen drei Primitive, die perfekt auf Auktionsanforderungen abgebildet werden:
- Postgres Changes: Abonnieren Sie INSERT-, UPDATE- und DELETE-Events in Ihren Bid- und Auctions-Tabellen. Wenn jemand ein Gebot abgibt, erhalten alle Abonnenten die neuen Zeilendaten innerhalb von Millisekunden.
- Broadcast: Senden Sie kurzlebige Nachrichten an Channel-Teilnehmer. Perfekt für "Sie wurden überboten"-Benachrichtigungen, die nicht persistent sein müssen.
- Presence: Verfolgen Sie, wer gerade eine Auktion beobachtet. Dies ermöglicht es Ihnen, "14 Bieter beobachten" in Ihrer UI zu zeigen und Ghost-Sitzungen zu erkennen.
Der Datenfluss sieht so aus:
- Der Bieter reicht ein Gebot über Ihr Frontend ein
- Ein RPC-Aufruf oder direktes Einfügen trifft Ihre
bids-Tabelle - Ein PostgreSQL-Trigger validiert den Gebotsbetrag und aktualisiert
auctions.current_high_bid - Supabase Realtime nimmt die WAL-Änderung auf und pusht sie an alle Abonnenten auf dem Auction-Channel
- Ein zweiter Trigger sendet ein Broadcast-Event, um den vorherigen höchsten Bieter zu benachrichtigen, dass er überboten wurde
- Jeder verbundene Client aktualisiert sein UI in Echtzeit
Die Latenz von der Gebotssendung bis zum UI-Update über alle Clients hinweg liegt typischerweise unter 100ms. Ich habe p99 in der Produktion auf Supabase's Pro Tier bei etwa 80-90ms gemessen.
Warum nicht einfach Polling verwenden?
Ich weiß, dass einige von Ihnen denken "Kann ich nicht einfach alle 500ms polllen?" Das können Sie. Aber bei 200 gleichzeitigen Bietern auf einer einzigen Auktion sind das 400 Anfragen pro Sekunde, die Ihre Datenbank für eine Auktion treffen. Multiplizieren Sie das mit 50 aktiven Auktionen und Sie sind bei 20.000 Queries pro Sekunde – die meisten davon geben nichts Neues zurück. WebSockets drehen dieses Modell um: null Queries, wenn sich nichts ändert, sofortige Updates, wenn etwas sich ändert.
Datenbankschema und Setup
Hier ist das Schema, das ich verwende. Es ist absichtlich einfach – Sie können es erweitern, aber die Kernstruktur behandelt die meisten Auktionstypen.
-- Auctions table
CREATE TABLE auctions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
item_name TEXT NOT NULL,
description TEXT,
starting_price DECIMAL(12,2) NOT NULL DEFAULT 0,
current_high_bid DECIMAL(12,2) DEFAULT 0,
highest_bidder_id UUID REFERENCES auth.users(id),
min_increment DECIMAL(12,2) DEFAULT 1.00,
status TEXT NOT NULL DEFAULT 'active'
CHECK (status IN ('scheduled', 'active', 'ended', 'sold', 'cancelled')),
starts_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ends_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + INTERVAL '30 minutes',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Bids table
CREATE TABLE bids (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
auction_id UUID NOT NULL REFERENCES auctions(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES auth.users(id),
amount DECIMAL(12,2) NOT NULL,
placed_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT positive_amount CHECK (amount > 0)
);
-- Index for fast bid lookups per auction
CREATE INDEX idx_bids_auction_amount ON bids(auction_id, amount DESC);
CREATE INDEX idx_bids_auction_time ON bids(auction_id, placed_at DESC);
-- Critical: enable replica identity for Realtime
ALTER TABLE auctions REPLICA IDENTITY FULL;
ALTER TABLE bids REPLICA IDENTITY FULL;
Die REPLICA IDENTITY FULL-Einstellung ist essentiell. Ohne sie erhält Supabase Realtime bei UPDATE- und DELETE-Events nur den Primärschlüssel – nicht die vollständigen Zeilendaten. Für ein Auktionssystem benötigen Sie die vollständige Payload, damit Clients Gebotbeträge aktualisieren können, ohne eine separate Abfrage zu stellen.
Aktivieren Sie die Realtime-Replikation
Im Supabase Dashboard gehen Sie zu Database → Replication und aktivieren Replikation für beide auctions- und bids-Tabellen. Alternativ können Sie dies mit SQL tun:
BEGIN;
-- Remove existing publication if it exists
DROP PUBLICATION IF EXISTS supabase_realtime;
-- Create publication with both tables
CREATE PUBLICATION supabase_realtime FOR TABLE auctions, bids;
COMMIT;
Row-Level Security
Überspringen Sie dies nicht. RLS ist Ihre serverseitige Validierungsschicht.
ALTER TABLE auctions ENABLE ROW LEVEL SECURITY;
ALTER TABLE bids ENABLE ROW LEVEL SECURITY;
-- Anyone can view active auctions
CREATE POLICY "Public auction viewing" ON auctions
FOR SELECT USING (status IN ('active', 'ended', 'sold'));
-- Authenticated users can view all bids on active auctions
CREATE POLICY "View bids on active auctions" ON bids
FOR SELECT USING (
EXISTS (
SELECT 1 FROM auctions
WHERE auctions.id = bids.auction_id
AND auctions.status = 'active'
)
);
-- Only authenticated users can place bids
CREATE POLICY "Place bids" ON bids
FOR INSERT WITH CHECK (
auth.uid() = user_id
AND EXISTS (
SELECT 1 FROM auctions
WHERE auctions.id = auction_id
AND auctions.status = 'active'
AND auctions.ends_at > NOW()
)
);
PostgreSQL-Trigger für Bid-Logik
Hier geschieht die echte Magie. Die Datenbank erzwingt alle Bid-Logik serverseitig – der Client kann nicht betrügen.
Bid-Validierung und Auction Update Trigger
CREATE OR REPLACE FUNCTION process_new_bid()
RETURNS TRIGGER AS $$
DECLARE
v_auction auctions%ROWTYPE;
BEGIN
-- Lock the auction row to prevent race conditions
SELECT * INTO v_auction
FROM auctions
WHERE id = NEW.auction_id
FOR UPDATE;
-- Validate auction is active
IF v_auction.status != 'active' THEN
RAISE EXCEPTION 'Auction is not active';
END IF;
-- Validate auction hasn't ended
IF v_auction.ends_at < NOW() THEN
RAISE EXCEPTION 'Auction has ended';
END IF;
-- Validate bid amount exceeds current high + minimum increment
IF NEW.amount < v_auction.current_high_bid + v_auction.min_increment THEN
RAISE EXCEPTION 'Bid must be at least % higher than current high bid of %',
v_auction.min_increment, v_auction.current_high_bid;
END IF;
-- Prevent self-outbidding
IF v_auction.highest_bidder_id = NEW.user_id THEN
RAISE EXCEPTION 'You are already the highest bidder';
END IF;
-- Update auction with new high bid
UPDATE auctions
SET
current_high_bid = NEW.amount,
highest_bidder_id = NEW.user_id,
updated_at = NOW()
WHERE id = NEW.auction_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER validate_and_process_bid
BEFORE INSERT ON bids
FOR EACH ROW
EXECUTE FUNCTION process_new_bid();
Das FOR UPDATE-Lock in der Auction-Zeile ist kritisch. Ohne es könnten zwei Gebote, die gleichzeitig ankommen, beide denselben current_high_bid lesen, beide Validierung bestehen und beide eingefügt werden. Das Lock serialisiert den Zugriff.
Broadcast Outbid-Benachrichtigungen
Dieser Trigger wird nach einem erfolgreichen Gebot abgerufen und sendet eine kurzlebige Benachrichtigung an den Auction-Channel:
CREATE OR REPLACE FUNCTION notify_outbid()
RETURNS TRIGGER AS $$
DECLARE
v_previous_bidder UUID;
BEGIN
-- Find who just got outbid
SELECT user_id INTO v_previous_bidder
FROM bids
WHERE auction_id = NEW.auction_id
AND id != NEW.id
ORDER BY amount DESC
LIMIT 1;
-- Broadcast outbid notification if there was a previous bidder
IF v_previous_bidder IS NOT NULL THEN
PERFORM realtime.send(
jsonb_build_object(
'auction_id', NEW.auction_id,
'new_high', NEW.amount,
'outbid_user', v_previous_bidder,
'new_leader', NEW.user_id
),
'outbid',
'auction:' || NEW.auction_id::text,
true
);
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER after_bid_notify
AFTER INSERT ON bids
FOR EACH ROW
EXECUTE FUNCTION notify_outbid();
Client-seitige Abonnements mit JavaScript
Jetzt verbinden wir das Frontend. Ich zeige dies mit vanilla JavaScript/React-Mustern – der gleiche Ansatz funktioniert, wenn Sie mit Next.js oder einem anderen Framework bauen.
Initialisieren Sie den Client
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
realtime: {
params: {
eventsPerSecond: 20 // Throttle for auction traffic
}
}
}
);
Der eventsPerSecond-Parameter ist wichtig. Bei einer heißen Auktion mit Dutzenden von Geboten pro Sekunde möchten Sie nicht 50 Mal pro Sekunde neu rendern. Zwanzig Updates pro Sekunde sind mehr als genug für ein glattes UI.
Abonnieren Sie einen Auction-Channel
function subscribeToAuction(auctionId, callbacks) {
const channel = supabase.channel(`auction:${auctionId}`);
channel
// Listen for new bids via Postgres Changes
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'bids',
filter: `auction_id=eq.${auctionId}`
}, (payload) => {
callbacks.onNewBid(payload.new);
})
// Listen for auction status changes
.on('postgres_changes', {
event: 'UPDATE',
schema: 'public',
table: 'auctions',
filter: `id=eq.${auctionId}`
}, (payload) => {
callbacks.onAuctionUpdate(payload.new);
})
// Listen for outbid broadcast notifications
.on('broadcast', { event: 'outbid' }, ({ payload }) => {
callbacks.onOutbid(payload);
})
// Track active bidders via Presence
.on('presence', { event: 'sync' }, () => {
const state = channel.presenceState();
const bidderCount = Object.keys(state).length;
callbacks.onPresenceUpdate(bidderCount, state);
})
.subscribe(async (status) => {
if (status === 'SUBSCRIBED') {
// Track this user's presence
await channel.track({
user_id: supabase.auth.getUser()?.data?.user?.id,
status: 'watching',
joined_at: new Date().toISOString()
});
}
});
return channel;
}
React Hook für Auction-Abonnements
import { useState, useEffect, useCallback } from 'react';
function useAuction(auctionId) {
const [auction, setAuction] = useState(null);
const [bids, setBids] = useState([]);
const [bidderCount, setBidderCount] = useState(0);
const [isOutbid, setIsOutbid] = useState(false);
useEffect(() => {
// Fetch initial state
async function loadAuction() {
const { data: auctionData } = await supabase
.from('auctions')
.select('*')
.eq('id', auctionId)
.single();
setAuction(auctionData);
const { data: bidData } = await supabase
.from('bids')
.select('*')
.eq('auction_id', auctionId)
.order('amount', { ascending: false })
.limit(20);
setBids(bidData || []);
}
loadAuction();
// Subscribe to real-time updates
const channel = subscribeToAuction(auctionId, {
onNewBid: (bid) => {
setBids(prev => [bid, ...prev].slice(0, 20));
setIsOutbid(false);
},
onAuctionUpdate: (updated) => setAuction(updated),
onOutbid: (payload) => {
const currentUser = supabase.auth.getUser()?.data?.user;
if (payload.outbid_user === currentUser?.id) {
setIsOutbid(true);
}
},
onPresenceUpdate: (count) => setBidderCount(count)
});
return () => {
supabase.removeChannel(channel);
};
}, [auctionId]);
const placeBid = useCallback(async (amount) => {
const user = (await supabase.auth.getUser()).data.user;
const { data, error } = await supabase
.from('bids')
.insert({
auction_id: auctionId,
amount: parseFloat(amount),
user_id: user.id
})
.select()
.single();
if (error) throw new Error(error.message);
return data;
}, [auctionId]);
return { auction, bids, bidderCount, isOutbid, placeBid };
}
Race Conditions und Bid-Validierung handhaben
Race Conditions sind die größte Fehlerquelle in Auktionssystemen. So handle ich sie.
Server-seitig: PostgreSQL macht die meiste Arbeit
Das SELECT ... FOR UPDATE in unserer Trigger-Funktion ist die erste Verteidigungslinie. Aber es gibt ein anderes Muster, das ich begonnen habe zu verwenden – Advisory Locks für hochfrequentierte Auktionen:
CREATE OR REPLACE FUNCTION place_bid_safe(
p_auction_id UUID,
p_user_id UUID,
p_amount DECIMAL
)
RETURNS TABLE(bid_id UUID, new_high DECIMAL) AS $$
DECLARE
v_lock_key BIGINT;
v_bid_id UUID;
BEGIN
-- Generate a deterministic lock key from auction UUID
v_lock_key := ('x' || left(p_auction_id::text, 15))::bit(64)::bigint;
-- Acquire advisory lock (blocks concurrent bids on same auction)
PERFORM pg_advisory_xact_lock(v_lock_key);
-- Now safe to insert (trigger handles validation)
INSERT INTO bids (auction_id, user_id, amount)
VALUES (p_auction_id, p_user_id, p_amount)
RETURNING id INTO v_bid_id;
RETURN QUERY
SELECT v_bid_id, p_amount;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
Rufen Sie dies vom Client auf, indem Sie die RPC von Supabase verwenden:
const { data, error } = await supabase.rpc('place_bid_safe', {
p_auction_id: auctionId,
p_user_id: user.id,
p_amount: bidAmount
});
Client-seitig: Optimistisches UI mit Rollback
Zeigen Sie das Gebot sofort in der UI an, aber seien Sie bereit, es zurückzurollen, wenn der Server es ablehnt:
async function handleBidSubmit(amount) {
const optimisticBid = {
id: crypto.randomUUID(),
amount,
user_id: user.id,
placed_at: new Date().toISOString(),
_optimistic: true
};
// Show immediately
setBids(prev => [optimisticBid, ...prev]);
try {
await placeBid(amount);
// Real bid will arrive via Realtime and replace optimistic one
} catch (err) {
// Remove optimistic bid on failure
setBids(prev => prev.filter(b => b.id !== optimisticBid.id));
showError(err.message);
}
}
Presence Tracking für aktive Bieter
Das Anzeigen, wie viele Menschen eine Auktion beobachten, schafft Dringlichkeit. Presence Tracking ist mit Supabase super einfach:
// Update user status when they start bidding
async function updatePresenceStatus(channel, status) {
await channel.track({
user_id: user.id,
status, // 'watching', 'bidding', 'won'
last_active: new Date().toISOString()
});
}
Auf der Anzeigeseite können Sie den Presence-Status unterteilen, um zu zeigen, wie viele aktiv bieten vs. nur beobachten:
function parseBidderStats(presenceState) {
const users = Object.values(presenceState).flat();
return {
total: users.length,
bidding: users.filter(u => u.status === 'bidding').length,
watching: users.filter(u => u.status === 'watching').length
};
}
Performance-Tuning und Produktionsüberlegungen
Drosseln und Debouncing
Ein Bieterwettbewerb kann dutzende Events pro Sekunde generieren. Hier ist, was ich konfiguriere:
- Server-seitig:
eventsPerSecond: 20auf der Supabase-Client-Konfiguration - Client-seitig: Debounce den Bid-Button bei 300ms, um Doppelklicks zu verhindern
- UI-Updates: Verwenden Sie
requestAnimationFramefür Bid-List-Animationen
Auction End Timing
Verlassen Sie sich nicht auf die Client-Clock. Verwenden Sie einen PostgreSQL Cron-Job über pg_cron:
-- Run every 10 seconds to close expired auctions
SELECT cron.schedule(
'close-expired-auctions',
'*/10 * * * * *',
$$
UPDATE auctions
SET status = CASE
WHEN highest_bidder_id IS NOT NULL THEN 'sold'
ELSE 'ended'
END
WHERE status = 'active'
AND ends_at <= NOW();
$$
);
Anti-Snipe-Erweiterung
Die meisten Auktionsplattformen erweitern die Deadline, wenn ein Gebot in den letzten Sekunden kommt:
-- Add to the process_new_bid trigger
IF v_auction.ends_at - NOW() < INTERVAL '30 seconds' THEN
UPDATE auctions
SET ends_at = ends_at + INTERVAL '30 seconds'
WHERE id = NEW.auction_id;
END IF;
Supabase Realtime vs. Alternativen
Ich habe die meisten davon in der Produktion verwendet. Hier ist ein ehrlicher Vergleich:
| Feature | Supabase Realtime | Pusher | Ably | Firebase RTDB | Socket.io (self-hosted) |
|---|---|---|---|---|---|
| Native DB-Synchronisierung | ✅ PostgreSQL WAL | ❌ Separater Service | ❌ Separater Service | ✅ JSON-Baum | ❌ Manuell |
| Latenz (p99) | ~80-100ms | ~60ms | ~50ms | ~100ms | ~40ms (abhängig von Infrastruktur) |
| Max Events/sec | 200k+ | 10k (Pro) | 50k | 100k | Unbegrenzt (Sie skalieren) |
| Auth-Integration | Built-in (RLS + JWT) | Custom | Token-basiert | Firebase Auth | Custom |
| Presence | ✅ Built-in | ✅ Built-in | ✅ Built-in | ✅ Built-in | ✅ Built-in |
| Kostenlos Tier | 500K MAU, 200 gleichzeitig | 100 Verbindungen | 6M msgs/mo | 1GB gespeichert | $0 (Hosting-Kosten) |
| Pro Pricing | $25/mo | $49/mo | $29/mo | Pay-as-you-go | ~$100-500/mo (AWS) |
| Beste für | DB-zentrische Echtzeit-Apps | Einfaches Pub/Sub | Hohe Zuverlässigkeit | Mobile Apps | Volle Kontrolle |
Für ein Auktionssystem speziell gewinnt Supabase, weil Ihre Gebote bereits in PostgreSQL sind. Sie müssen nicht zwischen einer Datenbank und einem separaten Pub/Sub-System synchronisieren. Das Gebot trifft die DB, die DB triggert den WebSocket-Push. Eine einzige Quelle der Wahrheit.
Wenn Sie auf einer Headless CMS-Architektur bauen, passt Supabase natürlich zur Inhaltsauslieferung, ohne einen weiteren Service hinzuzufügen.
Bereitstellung und Skalierung Ihres Auktionssystems
Für die meisten Projekte verarbeitet Supabase's verwaltete Pro Tier bei $25/Monat bequem bis zu 10.000 tägliche Auktionen. Hier ist, worauf Sie achten sollten:
- Verbindungslimits: Pro Tier gibt Ihnen 500 gleichzeitige Realtime-Verbindungen. Wenn Sie mehr benötigen, müssen Sie upgraden oder Connection Pooling auf dem Client implementieren.
- WAL-Größe: Hochvolumiges Bieten generiert bedeutende WAL-Traffic. Überwachen Sie Ihren Replikation-Slot, um Festplatte aufgebläht zu vermeiden.
- Channel-Count: Jede Auktion erhält ihren eigenen Channel. Mit Tausenden von aktiven Auktionen testen Sie, dass Ihr Client sich ordnungsgemäß von beendeten Auktionen abmeldet.
Für ein Frontend, das mit Astro oder Next.js gebaut ist, funktioniert der Supabase JS-Client identisch – stellen Sie einfach sicher, dass Sie ihn client-seitig für Realtime-Abonnements initialisieren.
Wenn Sie etwas bauen, das ernsthafte Skalierung bewältigen muss – Hunderttausende von gleichzeitigen Bietern – kontaktieren Sie uns. Wir haben diese Systeme in großem Maßstab konzipiert und können Ihnen helfen, die Fallstricke zu vermeiden. Sie können auch unsere Preisseite auf projektbasierte Engagements überprüfen.
Häufig gestellte Fragen
Wie viele gleichzeitige Bieter kann Supabase Realtime bewältigen? Supabase Realtime kann über 200.000 Events pro Sekunde über verteilte Server auf ihrer verwalteten Plattform verarbeiten. Der Pro Tier bei $25/Monat unterstützt bis zu 500 gleichzeitige Verbindungen pro Projekt. Für größere Auktionen bietet der Enterprise Tier benutzerdefinierte Limits, oder Sie können den Realtime-Server selbst hosten (er ist Open Source) auf Ihrer eigenen Infrastruktur.
Ist Supabase Realtime schnell genug für eine Live-Auktion? Ja. In meinen Tests liegt die End-to-End-Latenz von der Bid-Einfügung bis zur Client-Benachrichtigung durchschnittlich bei etwa 50-80ms, mit p99 unter 100ms. Zum Vergleich: Eine menschliche Reaktionszeit liegt bei etwa 200-300ms, sodass Gebote effektiv sofort erscheinen. Der Engpass ist selten Supabase – normalerweise ist es die Netzwerkverbindung des Client.
Wie verhindern Sie Race Conditions, wenn zwei Personen gleichzeitig bieten?
Verwenden Sie PostgreSQL's SELECT ... FOR UPDATE Zeilen-Level Locking in einer Trigger-Funktion, oder verwenden Sie Advisory Locks über pg_advisory_xact_lock(). Dies serialisiert die Bid-Verarbeitung pro Auktion, sodass nur ein Bid auf einmal validiert wird. Das "verlierende" Gebot wird dennoch validiert – es sieht einfach das aktualisierte High Bid vom Gewinner und erfolgt entweder (wenn es immer noch höher ist) oder schlägt mit einer angemessenen Fehlermeldung fehl.
Kann ich Supabase Realtime mit Next.js oder Astro verwenden?
Absolut. Der @supabase/supabase-js Client funktioniert in jeder JavaScript-Umgebung. Für Next.js initialisieren Sie den Supabase-Client in einer Client-Komponente (da Realtime Browser-WebSockets benötigt) und verwenden ihn in useEffect Hooks. Für Astro verwenden Sie es in client-seitigen interaktiven Islands. Der Abonnement-Code ist unabhängig von Ihrer Framework-Wahl identisch.
Was passiert, wenn die Verbindung eines Benutzers während der Auktion abbricht? Supabase Realtime versucht automatisch, sich erneut zu verbinden. Wenn der Client sich erneut verbindet und erneut abonniert, erhält er den aktuellen Status. Für kritische Auktionen empfehle ich auch, den neuesten Auction-Status über eine Standard-Abfrage bei Wiederverbindung abzurufen, um sicherzustellen, dass während des Trennungsfensters nichts verpasst wurde. Das Presence-System entfernt den getrennten Benutzer automatisch nach einem Timeout.
Wie handhabe ich die Genauigkeit der Auction-Endzeiten?
Verlassen Sie sich nie auf Client-seitige Timer für Auction-Endzeiten – sie können manipuliert werden. Verwenden Sie PostgreSQL's pg_cron Erweiterung, um alle 10 Sekunden serverseitig auf abgelaufene Auktionen zu prüfen und zu schließen. Senden Sie den Server-Zeitstempel an Clients, damit sie einen Countdown anzeigen können, aber die tatsächliche End-Bestimmung erfolgt immer in der Datenbank.
Ist Supabase Realtime kostenlos für kleine Projekte? Supabase's kostenlos Tier beinhaltet Realtime mit bis zu 200 gleichzeitigen Verbindungen und 500.000 monatlich aktiven Benutzern. Das reicht für eine Hobby-Auktionsseite oder ein MVP. Wenn Sie eine Produktions-Auktionsplattform mit bedeutendem Traffic betreiben, ist der Pro Tier bei $25/Monat mit $0.09/GB Egress der Ort, an dem Sie starten möchten. Es ist deutlich billiger als den Betrieb Ihrer eigenen WebSocket-Infrastruktur.
Wie teste ich ein Echtzeit-Bietungssystem lokal?
Verwenden Sie die Supabase CLI (supabase start), um eine lokale Supabase-Instanz mit aktiviertem Realtime auszuführen. Öffnen Sie mehrere Browser-Tabs, um mehrere Bieter zu simulieren. Zum Lasttesten verwende ich ein einfaches Node.js-Skript, das 100+ Supabase-Clients erstellt und sie gegen einander in einem Timer auf einer Auktion bieten lässt. Dies erfasst Race Conditions und hilft Ihnen, Ihren eventsPerSecond Parameter vor dem Produktionsstart zu tunen.