Polycrate API 0.14.15¶
Release-Datum: 19. März 2026
Typ: Hotfix
Highlights¶
- FTS DB-Bloat Hotfix – Der Reconciliation Loop triggerte nach dem FTS-Rollout (0.14.13) ~750 Tuple-Updates pro 5 Minuten mit vollständigen GIN-Index-Rebuilds; DB-Wachstum ~3,5 GB/Tag, Block I/O verdreifacht
- Signal-Guard Fix –
set_state()undadd_condition()nutzen jetztsave(update_fields=...)damit der FTS-Signal-Guard state-only Saves korrekt herausfiltert - Suche: Infrastruktur-Namen mit Bindestrich –
search_type="websearch"interpretierte-als NOT-Operator; jetzt"plain"für korrekte Ergebnisse bei Namen wieprod-k8s-01,aycloud-fra1
Artefakte¶
Docker Image¶
Block¶
Fixes¶
FTS GIN-Reindex-Storm: state und kind aus Signal-Trigger entfernt¶
Ursache: Nach dem FTS-Rollout (0.14.13) enthielt _SEARCH_BASE_FIELDS die Felder state und kind. Der Reconciliation Loop ruft set_state() bei jedem Durchlauf auf – damit wurde bei jeder Zustandsänderung ein vollständiger GIN-Index-Rebuild auf der SearchIndex-Tabelle ausgelöst.
Effekt: - ~750 Tuple-Updates / 5 Minuten auf SearchIndex - GIN-Index fastupdate-Pending-List wurde permanent geleert und neu befüllt → I/O-Bursts - MVCC-Bloat: Autovacuum kam nicht nach → DB-Wachstum ~3,5 GB/Tag (25 GB → 45 GB in 6 Tagen) - Block I/O verdreifacht (1000 → 3000 Blöcke/5min), WAL-Aktivität stark erhöht - Bis zu 45 blockierte Queries, eine Transaktion mit 33 Minuten Laufzeit
Fix: state und kind aus _SEARCH_BASE_FIELDS entfernt. Diese Felder sind Filter-only auf SearchIndex — ihr Wert beeinflusst nicht, was ein User in die Suchmaske tippt.
# signals.py
_SEARCH_BASE_FIELDS = frozenset([
"name", "display_name", "description",
"archived", "labels",
"organization_id", "organization",
"workspace_id", "workspace",
])
Signal-Guard: set_state() und add_condition() nutzen update_fields¶
Ursache: Der FTS-Signal post_save enthält einen Guard, der Re-Indexing überspringt wenn update_fields gesetzt ist und keine FTS-relevanten Felder betroffen sind. set_state() rief self.save() ohne update_fields auf — der Guard griff daher nie.
Zusätzlich: Im WARNING-Branch von set_state() existierte ein bare save() das den State nicht veränderte, aber dennoch den Signal-Guard triggerte.
Fix:
# models.py — set_state()
self.save(update_fields=["state", "last_state", "last_state_change"])
# models.py — add_condition()
self.save(update_fields=["conditions"])
Der no-op-save() im WARNING-Branch wurde entfernt.
Suche: search_type="plain" statt "websearch"¶
Ursache: SearchQuery verwendete search_type="websearch". PostgreSQL's WebSearch-Parser interpretiert - als NOT-Operator. Suchanfragen wie prod-k8s-01 wurden intern zu prod AND NOT k8s AND NOT 01 — valide Objekte blieben unsichtbar.
Fix:
Nach dem Deployment¶
Nach dem Deployment empfiehlt sich ein manuelles VACUUM ANALYZE auf der SearchIndex-Tabelle um den aufgelaufenen MVCC-Bloat sofort zu bereinigen und die Autovacuum-Aggressivität anzupassen: