Skip to content

Commit c50c2ac

Browse files
committed
fix(search): require the purge preflight's trigger to fire and call the retiring function
- embedding_search_sync must be enabled for ordinary writes (origin or always, not replica-only) and call public.sync_embedding_search - Drop the redundant client port option; postgres.js reads the URL port
1 parent 2d873a9 commit c50c2ac

2 files changed

Lines changed: 15 additions & 3 deletions

File tree

‎packages/db/scripts/purge-search-projection.integration.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,24 @@ describe('Search candidate retirement in PostgreSQL', () => {
392392
await applyMigration()
393393
await sql`ALTER TABLE embedding DISABLE TRIGGER embedding_search_sync`
394394
expect(runPurge('--execute', '--pause-ms', '0').status).toBe(1)
395+
// A replica-only trigger never fires for application writes.
396+
await sql`ALTER TABLE embedding ENABLE REPLICA TRIGGER embedding_search_sync`
397+
expect(runPurge('--execute', '--pause-ms', '0').status).toBe(1)
398+
await sql`ALTER TABLE embedding ENABLE TRIGGER embedding_search_sync`
399+
400+
await sql.unsafe(`CREATE FUNCTION public.other_embedding_sync()
401+
RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN RETURN NEW; END; $$`)
402+
await sql.unsafe(`CREATE OR REPLACE TRIGGER embedding_search_sync AFTER INSERT ON embedding
403+
FOR EACH ROW EXECUTE FUNCTION public.other_embedding_sync()`)
404+
expect(runPurge('--execute', '--pause-ms', '0').status).toBe(1)
395405
expect(await candidateCount('search')).toBe(3)
396406
} finally {
397407
await sql`ALTER TABLE embedding ENABLE TRIGGER embedding_search_sync`
408+
await sql.unsafe(provisioned.sync.replace('CREATE TRIGGER', 'CREATE OR REPLACE TRIGGER'))
409+
await sql`DROP FUNCTION IF EXISTS public.other_embedding_sync()`
398410
await applyMigration()
399411
}
412+
expect((await definitions())[0].sync).toBe(provisioned.sync)
400413
const dryRun = runPurge()
401414
expect(dryRun.stdout).toContain('"projectionRetired":true')
402415
const execute = runPurge('--execute', '--pause-ms', '0')

‎packages/db/scripts/purge-search-projection.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ export function connectOperatorDatabase(rawUrl: string | undefined): Sql {
134134
clientUrl.searchParams.delete('sslmode')
135135
clientUrl.searchParams.delete('sslrootcert')
136136
return postgres(clientUrl.toString(), {
137-
port: Number(url.port || '5432'),
138137
ssl: hosted ? 'verify-full' : false,
139138
max: 1,
140139
prepare: false,
@@ -153,7 +152,7 @@ export function connectOperatorDatabase(rawUrl: string | undefined): Sql {
153152

154153
/**
155154
* Whether migration 0449 is live: `public.sync_embedding_search` has the body that deletes a
156-
* Search chunk's candidate row, and its `embedding_search_sync` trigger is enabled. Before that,
155+
* Search chunk's candidate row, and the enabled `embedding_search_sync` trigger calls it. Before that,
157156
* chunk writes keep projecting the rows a purge deletes.
158157
*/
159158
async function isProjectionRetired(sql: Sql): Promise<boolean> {
@@ -162,7 +161,7 @@ async function isProjectionRetired(sql: Sql): Promise<boolean> {
162161
EXISTS (
163162
SELECT 1 FROM pg_trigger
164163
WHERE tgrelid = to_regclass('public.embedding') AND tgname = 'embedding_search_sync'
165-
AND tgenabled <> 'D'
164+
AND tgenabled IN ('O', 'A') AND tgfoid = to_regproc('public.sync_embedding_search')
166165
) AS trigger_enabled`
167166
return (
168167
live.trigger_enabled && live.source !== null && isCurrentSyncEmbeddingSearchSource(live.source)

0 commit comments

Comments
 (0)