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

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:

  1. Der Bieter reicht ein Gebot über Ihr Frontend ein
  2. Ein RPC-Aufruf oder direktes Einfügen trifft Ihre bids-Tabelle
  3. Ein PostgreSQL-Trigger validiert den Gebotsbetrag und aktualisiert auctions.current_high_bid
  4. Supabase Realtime nimmt die WAL-Änderung auf und pusht sie an alle Abonnenten auf dem Auction-Channel
  5. Ein zweiter Trigger sendet ein Broadcast-Event, um den vorherigen höchsten Bieter zu benachrichtigen, dass er überboten wurde
  6. 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: 20 auf der Supabase-Client-Konfiguration
  • Client-seitig: Debounce den Bid-Button bei 300ms, um Doppelklicks zu verhindern
  • UI-Updates: Verwenden Sie requestAnimationFrame fü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.