FOR UPDATE places row-level locks on selected queue messages, allowing only one concurrent consumer to work with each returned row. Locks remain until the transaction commits or rolls back. section 11.2
Concurrent queue consumers
A dequeue function selects new messages in creation order, locks them, and updates their status: WITH new_messages AS (SELECT id FROM mq.queue WHERE status = 'new' ORDER BY created_at FOR UPDATE SKIP LOCKED LIMIT messages_cnt) UPDATE mq.queue SET status = 'processing' FROM new_messages WHERE mq.queue.id = new_messages.id. SKIP LOCKED lets other consumers bypass rows already locked, so processing continues in parallel. section 11.2
Within BEGIN...COMMIT, locks survive alongside business logic and release at COMMIT or rollback. Without an explicit transaction, the function’s implicit transaction releases them when execution finishes. section 11.2

