I am implementing a simple pessimistic locking mechanism using Postgres as a medium. The goal is that multiple instances of an application can simultaneously acquire locks on distinct sets of users. The app instances are not trying to lock specific users. Instead they will take any user locks they can get.
Say, for example, we have three instances of the app running and there are currently 5 users that are not locked. All three instances attempt to acquire locks on up to three users at the same time. Their requests are served in arbitrary order. Ideally, the first instance served would acquire 3 user locks, the second would acquire 2 and the third would acquire no locks.
So far I have not been able to write a Query that accomplishes this. I'll show you my best attempt so far.
Here are the tables for the example:
CREATE TABLE my_locks (
id bigserial PRIMARY KEY,
user_id bigint NOT NULL UNIQUE
);
CREATE TABLE my_users (
id bigserial PRIMARY KEY,
user_name varchar(50) NOT NULL
);
And this is the Query for acquiring locks:
INSERT INTO my_locks(user_id)
SELECT u.id
FROM my_users AS u
LEFT JOIN my_locks
AS l
ON u.id = l.user_id
WHERE l.user_id IS NULL
LIMIT 3
RETURNING *
I had hoped that folding the collecting of lockable users and the insertion of the locks into the database into a single query would ensure that multiple simultaneous requests would be processed in their entirety one after the other.
It doesn't work that way. If applied to the above example where three instances use this Query to simultaneously acquire locks on a pool of 5 users, one instance acquires three locks and the other instances receive an error for attempting to insert locks with non-unique user-IDs.
This is not ideal, because it prevents the locking mechanism from scaling. There are a number of workarounds to deal with this, but what I am looking for is a database-level solution. Is there a way to tweak the Query or DB configuration in such a way that multiple app instances can (near-)simultaneously acquire the maximum available number of locks in perfectly distinct sets?