@@ -38,26 +38,45 @@ export class SQLiteDatabaseAdapter implements DatabaseAdapter {
3838 [ now ]
3939 ) ;
4040
41+ // Atomically reserve a job using UPDATE with RETURNING (if supported) or UPDATE + SELECT
42+ // For SQLite, we'll use a subquery to atomically reserve the next available job
43+ const result = await run (
44+ `UPDATE jobs SET
45+ status = 'reserved',
46+ reserve_time = ?,
47+ expire_time = ?
48+ WHERE id = (
49+ SELECT id FROM jobs
50+ WHERE status = 'waiting'
51+ AND (delay_time IS NULL OR delay_time <= ?)
52+ ORDER BY priority DESC, push_time ASC
53+ LIMIT 1
54+ )` ,
55+ [ now , now + 300 * 1000 , now ] // Default 5 minute TTR for now
56+ ) ;
57+
58+ // Check if we actually updated a row
59+ if ( ( result as any ) . changes === 0 ) {
60+ return null ;
61+ }
62+
63+ // Now get the job we just reserved
4164 const job = await get (
4265 `SELECT * FROM jobs
43- WHERE status = 'waiting '
44- AND (delay_time IS NULL OR delay_time < = ?)
45- ORDER BY priority DESC, push_time ASC
66+ WHERE status = 'reserved '
67+ AND reserve_time = ?
68+ ORDER BY reserve_time DESC
4669 LIMIT 1` ,
4770 [ now ]
4871 ) as any ;
4972
5073 if ( ! job ) return null ;
5174
52- // Use the job's TTR value, not the polling timeout
53- const jobTtr = job . ttr || 300 ; // Default to 5 minutes if no TTR
75+ // Update with the correct TTR from the job
76+ const jobTtr = job . ttr || 300 ;
5477 await run (
55- `UPDATE jobs SET
56- status = 'reserved',
57- reserve_time = ?,
58- expire_time = ?
59- WHERE id = ?` ,
60- [ now , now + jobTtr * 1000 , job . id ]
78+ `UPDATE jobs SET expire_time = ? WHERE id = ?` ,
79+ [ now + jobTtr * 1000 , job . id ]
6180 ) ;
6281
6382 return {
0 commit comments