I would like to find out a good way to go about implementing a jobs queue using postgres and PDO (php).
Basically I have an even
As it is presented, this is not possible. PostgreSQL doesn't have dirty reads, and QUERY1
is pointless since its effect will be overrided by QUERY2
before ever being visible.
But even if it was committed and visible immediately (if committed independantly), this wouldn't be satisfying anyway. In a high concurrency environment, the time between the SELECT of a row in the queue and its UPDATE with the ongoing
state is enough for another worker to SELECT it too and create the confusion you want to avoid.
I think a close alternative to your design that should work can be achieved by replacing your QUERY1
with an advisory lock on the queue ID.
Pseudo-code:
BEGIN;
SELECT pg_try_advisory_xact_lock(3) INTO result;
IF result=true THEN
-- grabbed the exclusive right to process this entry
-- recheck the status now that the lock is taken
SELECT status INTO var_status FROM events WHERE id=3;
IF var_status='needs-to-be-done' THEN
-- do the work...
-- work is done
UPDATE events SET status = 'resolved' WHERE id = 3;
END IF;
ELSE
-- nothing to do, another worker is on it
END IF;
COMMIT;
This kind of lock is automatically released at the end of the transaction. Contrary to the SELECT followed by UPDATE, the lock is guaranteed to be granted or denied atomically.