Documentation for method protect-or-queue-on-recursion assembled from the following pages:

Class: Lock::Async §

From Lock::Async

(Lock::Async) method protect-or-queue-on-recursion §

Defined as:

method protect-or-queue-on-recursion(Lock::Async:D: &code)

When calling protect on a Lock::Async instance that is already locked, the method is forced to block until the lock gets unlocked. protect-or-queue-on-recursion avoids this issue by either behaving the same as protect if the lock is unlocked or the lock was locked by something outside the caller chain, returning Nil, or queueing the call to &code and returning a Promise if the lock had already been locked at another point in the caller chain.

my Lock::Async $lock .= new;
my Int         $count = 0;
 
# The lock is unlocked, so the code runs instantly. 
$lock.protect-or-queue-on-recursion({
    $count++
});
 
# Here, we have caller recursion. The outer call only returns a Promise 
# because the inner one does. If we try to await the inner call's Promise 
# from the outer call, the two calls will block forever since the inner 
# caller's Promise return value is just the outer's with a then block. 
$lock.protect-or-queue-on-recursion({
    $lock.protect-or-queue-on-recursion({
        $count++
    }).then({
        $count++
    })
});
 
# Here, the lock is locked, but not by anything else on the caller chain. 
# This behaves just like calling protect would in this scenario. 
for 0..^2 {
    $lock.protect-or-queue-on-recursion({
        $count++;
    });
}
 
say $count# OUTPUT: 5