3.8 KiB
search
das komplette serverjonas search
crawler.py– PostgreSQL-Crawler, baut den Suchindex auflauncher.py– startet/überwacht den Crawler und rollt Updates aus (siehe unten)search/– Suchmaschine darüber (CLI + HTTP-API), siehe search/README.mdweb/– Statistik-Webseitefix_pages_search_vector_trigger.sql– einmalig laufen lassen: kappelt den Text, der im DB-Triggerpages_search_vector_update()into_tsvector()einfließt (Postgres hartes Limit: 1.048.575 Bytes protsvector)
Sehr große Seiten / tsvector-Limit
PostgreSQL begrenzt einen einzelnen tsvector-Wert hart auf 1.048.575 Bytes
(nicht konfigurierbar). Der Trigger pages_search_vector_update() baut diesen
aus der content-Spalte – Seiten mit sehr viel Text (beobachtet: ~2 MB, z. B.
pkg.go.dev/...?tab=importedby) haben den Insert dadurch mit
ProgramLimitExceeded abgebrochen und alle Worker crashen lassen.
Dagegen wirken drei Maßnahmen zusammen:
- DB-Trigger (empfohlen, einmalig einspielen):
fix_pages_search_vector_trigger.sqlersetzt die Trigger-Funktion so, dass nur die ersten 200.000 Zeichen into_tsvector()einfließen. Der volle Text bleibt incontentgespeichert, nur der Suchindex ist gekürzt. Vor dem Einspielen die eigene Funktions-Version prüfen:SELECT prosrc FROM pg_proc WHERE proname = 'pages_search_vector_update'; - Im Crawler:
save_page()kappelt den Inhalt vor dem Insert zusätzlich aufCONTENT_INDEX_MAX_CHARS(200.000 Zeichen) – wirkt sofort, auch ohne Trigger-Fix. Überlange Seiten werden dann normal gespeichert. - Fehlerbehandlung: Sollte der Insert trotzdem an einem Datenbank-Limit
scheitern, fängt der Worker
ProgramLimitExceededab, loggt die URL als Warnung, rollt die Transaktion zurück, markiert den Queue-Eintrag alsfailed(kein endloses Wiederholen) und läuft weiter, statt zu sterben.
Zusätzlich werden bekannt wertlose URLs (pkg.go.dev/...?tab=importedby –
Megabyte-große reine Rückverweis-Listen) über SKIP_URL_PATTERNS schon vor dem
Fetch übersprungen und als done markiert.
Rolling Updates (Generation-Mechanismus)
Zentrale Tabelle (eine Zeile, id = 1):
CREATE TABLE IF NOT EXISTS deployment_state (
id INTEGER PRIMARY KEY,
generation BIGINT NOT NULL,
required_version INTEGER NOT NULL
);
Ablauf:
- Einmalig initialisieren:
python3 crawler.py --init-deployment - Launcher starten:
python3 launcher.py(startet + überwacht den Crawler) - Neue Version verteilen:
- Neue
crawler.pymit erhöhterJONASSEARCH_CRAWLER_VERSIONbereitstellen (Update-Quelle im.envsetzen oder Datei nachreleases/<VERSION>/crawler.pylegen) python3 launcher.py --check-update→ neue Version wird gestaget → geprüft (--self-update) → aktiviert → erst dann wird die Generation in PostgreSQL erhöht (--update-deployment)
- Neue
- Alle laufenden alten Crawler merken das beim nächsten sicheren Punkt
(vor jedem relevanten Commit bzw. spätestens nach
JONASSEARCH_UPDATE_CHECK_SECONDSim Hintergrund-Check), rollen ihre offene Transaktion sauber zurück und beenden sich mit Exit-Code 42 – nie mitten in einer Transaktion, kein hartes Killen. - Der jeweilige Launcher erkennt 42 und startet die bereits bereitgestellte neue Version, die die neue Generation beim Start liest.
Exit-Codes des Crawlers: 0 = normal beendet, 1 = Fehler/Crash,
42 = ausschließlich „Update erforderlich".
Nützliche Befehle:
python3 crawler.py --version # installierte Version
python3 launcher.py --status # Generation + Versionen anzeigen
python3 crawler.py --self-update 2 # gestagte Release prüfen (ohne zu aktivieren)
python3 crawler.py --update-deployment 2 # Generation+1 und required_version=2 setzen