@@ -180,11 +180,43 @@ func (t *Table[T, PT, IDT]) WithTx(tx pgx.Tx) *Table[T, PT, IDT] {
180180 }
181181}
182182
183- // LockForUpdates locks and processes records using PostgreSQL's FOR UPDATE SKIP LOCKED pattern
184- // for safe concurrent processing. Each record is processed exactly once across multiple workers.
185- // Records are automatically updated after updateFn() completes. Keep updateFn() fast to avoid
186- // holding the transaction. For long-running work, update status to "processing" and return early,
187- // then process asynchronously. Use defer LockOneForUpdate() to update status to "completed" or "failed".
183+ // LockForUpdate locks and updates one record using PostgreSQL's FOR UPDATE SKIP LOCKED pattern
184+ // within a database transaction for safe concurrent processing. The record is processed exactly
185+ // once across multiple workers. The record is automatically updated after updateFn() completes.
186+ //
187+ // Keep updateFn() fast to avoid holding the transaction. For long-running work, update status
188+ // to "processing" and return early, then process asynchronously. Use defer LockForUpdate()
189+ // to update status to "completed" or "failed".
190+ //
191+ // Returns ErrNoRows if no matching records are available for locking.
192+ func (t * Table [T , PT , IDT ]) LockForUpdate (ctx context.Context , where sq.Sqlizer , orderBy []string , updateFn func (record PT )) error {
193+ var noRows bool
194+
195+ err := t .LockForUpdates (ctx , where , orderBy , 1 , func (records []PT ) {
196+ if len (records ) > 0 {
197+ updateFn (records [0 ])
198+ } else {
199+ noRows = true
200+ }
201+ })
202+ if err != nil {
203+ return fmt .Errorf ("lock for update one: %w" , err )
204+ }
205+
206+ if noRows {
207+ return ErrNoRows
208+ }
209+
210+ return nil
211+ }
212+
213+ // LockForUpdates locks and updates records using PostgreSQL's FOR UPDATE SKIP LOCKED pattern
214+ // within a database transaction for safe concurrent processing. Each record is processed exactly
215+ // once across multiple workers. Records are automatically updated after updateFn() completes.
216+ //
217+ // Keep updateFn() fast to avoid holding the transaction. For long-running work, update status
218+ // to "processing" and return early, then process asynchronously. Use defer LockForUpdate()
219+ // to update status to "completed" or "failed".
188220func (t * Table [T , PT , IDT ]) LockForUpdates (ctx context.Context , where sq.Sqlizer , orderBy []string , limit uint64 , updateFn func (records []PT )) error {
189221 // Check if we're already in a transaction
190222 if t .DB .Query .Tx != nil {
@@ -227,31 +259,3 @@ func (t *Table[T, PT, IDT]) lockForUpdatesWithTx(ctx context.Context, pgTx pgx.T
227259
228260 return nil
229261}
230-
231- // LockForUpdate locks and processes one record using PostgreSQL's FOR UPDATE SKIP LOCKED pattern
232- // for safe concurrent processing. The record is processed exactly once across multiple workers.
233- // The record is automatically updated after updateFn() completes. Keep updateFn() fast to avoid
234- // holding the transaction. For long-running work, update status to "processing" and return early,
235- // then process asynchronously. Use defer LockForUpdate() to update status to "completed" or "failed".
236- //
237- // Returns ErrNoRows if no matching records are available for locking.
238- func (t * Table [T , PT , IDT ]) LockForUpdate (ctx context.Context , where sq.Sqlizer , orderBy []string , updateFn func (record PT )) error {
239- var noRows bool
240-
241- err := t .LockForUpdates (ctx , where , orderBy , 1 , func (records []PT ) {
242- if len (records ) > 0 {
243- updateFn (records [0 ])
244- } else {
245- noRows = true
246- }
247- })
248- if err != nil {
249- return fmt .Errorf ("lock for update one: %w" , err )
250- }
251-
252- if noRows {
253- return ErrNoRows
254- }
255-
256- return nil
257- }
0 commit comments