11/** Real PostgreSQL cancellation must roll back preparation and release its advisory lock. */
22import { withUtcTimestamps } from '@sim/db/timestamps'
33import { getPostgresErrorCode } from '@sim/utils/errors'
4- import { sleep } from '@sim/utils/helpers'
54import { generateId } from '@sim/utils/id'
65import { drizzle , type PostgresJsDatabase } from 'drizzle-orm/postgres-js'
76import postgres from 'postgres'
@@ -138,7 +137,7 @@ describe('workspace file search dispatch PostgreSQL deadlines', () => {
138137 await expectAdvisoryLockReleased ( )
139138 } , 20_000 )
140139
141- it ( 'releases committed claims after contention exceeds the preparation lock deadline ' , async ( ) => {
140+ it ( 'releases committed claims without the preparation deadlines ' , async ( ) => {
142141 const fileId = generateId ( )
143142 const workspaceId = generateId ( )
144143 await connection `UPDATE workspace_file_search_backfill SET completed_at = now()`
@@ -149,43 +148,46 @@ describe('workspace file search dispatch PostgreSQL deadlines', () => {
149148 VALUES (${ fileId } , ${ workspaceId } , '2026-09-16', 'pending', now())`
150149 await connection `INSERT INTO workspace_file_search_dispatch_queue
151150 (workspace_id, enqueued_at, updated_at) VALUES (${ workspaceId } , now(), now())`
151+ await connection `CREATE TABLE cleanup_timeouts (
152+ lock_timeout text, statement_timeout text, transaction_timeout text
153+ )`
154+ await connection `CREATE FUNCTION record_cleanup_timeouts() RETURNS trigger LANGUAGE plpgsql AS $$
155+ BEGIN
156+ INSERT INTO cleanup_timeouts VALUES (
157+ current_setting('lock_timeout'),
158+ current_setting('statement_timeout'),
159+ current_setting('transaction_timeout')
160+ );
161+ RETURN NEW;
162+ END
163+ $$`
164+ await connection `CREATE TRIGGER record_cleanup_timeouts AFTER UPDATE OF dispatched_at
165+ ON workspace_file_search_index FOR EACH ROW
166+ WHEN (OLD.dispatched_at IS NOT NULL AND NEW.dispatched_at IS NULL)
167+ EXECUTE FUNCTION record_cleanup_timeouts()`
152168
153169 const enqueueError = new Error ( 'Queue unavailable' )
154- let blocker : Promise < unknown > | undefined
155- mocks . batchTrigger . mockImplementationOnce ( async ( ) => {
156- let locked = ( ) => { }
157- const lockReady = new Promise < void > ( ( resolve ) => {
158- locked = resolve
159- } )
160- blocker = connection . begin ( async ( tx ) => {
161- await tx `SELECT file_id FROM workspace_file_search_index WHERE file_id = ${ fileId } FOR UPDATE`
162- locked ( )
163- await sleep ( 3_000 )
164- } )
165- await Promise . race ( [ lockReady , blocker ] )
166- throw enqueueError
167- } )
170+ mocks . batchTrigger . mockRejectedValueOnce ( enqueueError )
168171
169- try {
170- await expect ( dispatchWorkspaceFileSearchIndexJobs ( ) ) . rejects . toBe ( enqueueError )
171- expect ( mocks . batchTrigger ) . toHaveBeenCalledWith ( 'workspace-file-search-index' , [
172- expect . objectContaining ( {
173- payload : {
174- fileId,
175- workspaceId,
176- sourceContentUpdatedAt : '2026-09-16T00:00:00.000Z' ,
177- } ,
178- } ) ,
179- ] )
180- const [ index ] = await connection `SELECT dispatched_at FROM workspace_file_search_index
181- WHERE file_id = ${ fileId } `
182- expect ( index . dispatched_at ) . toBeNull ( )
183- const [ queued ] =
184- await connection `SELECT workspace_id FROM workspace_file_search_dispatch_queue
185- WHERE workspace_id = ${ workspaceId } `
186- expect ( queued . workspace_id ) . toBe ( workspaceId )
187- } finally {
188- await blocker
189- }
172+ await expect ( dispatchWorkspaceFileSearchIndexJobs ( ) ) . rejects . toBe ( enqueueError )
173+ expect ( mocks . batchTrigger ) . toHaveBeenCalledWith ( 'workspace-file-search-index' , [
174+ expect . objectContaining ( {
175+ payload : {
176+ fileId,
177+ workspaceId,
178+ sourceContentUpdatedAt : '2026-09-16T00:00:00.000Z' ,
179+ } ,
180+ } ) ,
181+ ] )
182+ const [ index ] = await connection `SELECT dispatched_at FROM workspace_file_search_index
183+ WHERE file_id = ${ fileId } `
184+ expect ( index . dispatched_at ) . toBeNull ( )
185+ const [ queued ] = await connection `SELECT workspace_id FROM workspace_file_search_dispatch_queue
186+ WHERE workspace_id = ${ workspaceId } `
187+ expect ( queued . workspace_id ) . toBe ( workspaceId )
188+ const timeouts = await connection `SELECT * FROM cleanup_timeouts`
189+ expect ( [ ...timeouts ] ) . toEqual ( [
190+ { lock_timeout : '0' , statement_timeout : '0' , transaction_timeout : '0' } ,
191+ ] )
190192 } )
191193} )
0 commit comments