-
Notifications
You must be signed in to change notification settings - Fork 8
Description
As already stated in #46, we have a problem with the unlock all being run too often.
Originally, I thought that it was a problem with running it on connections that never were used to acquire a lock. I "solved" that by using a separate engine/connection pool for locking.
I looked in to the issue again because I saw an increase in the number of unlock all calls lately. I found another problem in this investigation.
In our application, we have multiple parts that use locking. For simplicity's sake, let's say we have a Locker instance for each of our work queues. We added a new type of queue lately and therefore roughly doubled the the number of Locker instances. We expected to have double the amount of unlock all calls. We observed a way larger increase though.
Consider the following example:
import random
import pals
import sqlalchemy as sa
engine = sa.create_engine("postgresql://...")
N_LOCKERS = 3
N_LOCKS = 5
lockers = []
for i in range(N_LOCKERS):
locker = pals.Locker(f"app_{i}", create_engine_callable=lambda: engine)
lockers.append(locker)
for i in range(N_LOCKS):
locker = lockers[random.randint(0, N_LOCKERS - 1)]
lock = locker.lock("somelock")
print("Acquiring lock", locker.app_name)
lock.acquire()
lock.release()
print("Released lock", locker.app_name)This generates the following output (with a print statement on the on_conn_checkin function):
Acquiring lock app_2
Connection checkin event fired for Locker app_0
Connection checkin event fired for Locker app_1
Connection checkin event fired for Locker app_2
Released lock app_2
Acquiring lock app_1
Connection checkin event fired for Locker app_0
Connection checkin event fired for Locker app_1
Connection checkin event fired for Locker app_2
Released lock app_1
For any lock we see 3 checkin events (and thus 3 unlock all calls). Now adding more queues to our application roughly doubled N_LOCKERS and N_LOCKS, so we saw a roughly 4 times more unlock all calls.
I see two ways forward:
- I pick up on Only run pg_advisory_unlock_all if necessary. #46 again, vendor it and add tests
- I implement another solution that will only register the
on_conn_checkinhandler once on the same engine object.
Which one of the two do you find more promising?