I'm confused about how Civi::lockManager is supposed to be used in handling sql-level locks on certain processes.
I'm looking at a few existing code usages (as in Omnipay here and in civicrm core here). These are all using essentially this logic:
Listing 1:
$lock = Civi::lockManager()->acquire($PROPERLY_FORMATTED_LOCK_NAME);
if (!$lock->isAcquired()) {
// This entity is locked, so don't do anything
}
else {
// This entity is not locked, so go ahead and do that thing.
}
However, my rather naive testing shows that $lock>isAcquired($ANYTHING)
will always return TRUE. Consider this simple test script and its output:
Listing 2:
$ cat /tmp/locktest.php
<?php
$lockName = 'data.contribute.contribution.1';
$lock = Civi::lockManager()->acquire($lockName);
echo("lock is acquired:" . $lock->isAcquired()) . "\n";
$lock = Civi::lockManager()->acquire($lockName);
echo("lock is acquired:" . $lock->isAcquired()) . "\n";
$ cv scr /tmp/locktest.php
lock is acquired:1
lock is acquired:1
(From my reading, this seems reasonable, considering that mysql GET_LOCK()
(which is always called by acquire()
) is designed to allow multiple simultaneous locks of the same name. (Reference mysql docs). I.e., if you ask to acquire a lock of name 'x', mysql will always give it to you. The important step would be using IS_FREE_LOCK()
to test whether the lock is actually free.)
Given the output in Listing 2, how is it possible that the code in Listing 1 is actually testing for the pre-existence of a named lock and avoiding repeat action if that lock is in place?
get_lock('bambi', 100)
Then I can run that over & over in that session and I will get the lock (result = 1) . In the other session I keep running it and get a result of 0 - because the other session has the lock. One thing I noticed in the code is that the timeout seems to be only 3 seconds - which might be enough but is less than I expected I then run itsleep()
in there long enough to keep locktest.php running in one terminal, and then run locktest.php in another terminal, that second instance will pause atCivi::lockManager()->acquire()
until the first process's lock is released. If you'd like, please make an answer, because I think you've answered it. Else I will at some point.