diff --git a/README.md b/README.md index 66a3070..0bb608d 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,12 @@ $lock = new Lock(RPC::create('tcp://127.0.0.1:6001')); ### Acquire lock -Locks a resource so that it can be accessed by one process at a time. When a resource is locked, other processes that -attempt to lock the same resource will be blocked until the lock is released. +Locks a resource so that it can be accessed by one process at a time. + +By default the call is **non-blocking**: if the resource is already locked, it returns `false` almost immediately +(the RoadRunner server caps the default `waitTTL` window at `1ms`). Pass a positive `waitTTL` to block until the lock +is released — the call then returns the lock id as soon as the lock becomes free, or `false` when the `waitTTL` +timeout elapses. ```php $id = $lock->lock('pdf:create'); @@ -59,9 +63,9 @@ $id = $lock->lock('pdf:create', ttl: 10); $id = $lock->lock('pdf:create', ttl: new \DateInterval('PT10S')); // Acquire lock and wait 5 seconds until lock will be released -$id = $lock->lock('pdf:create', wait: 5); +$id = $lock->lock('pdf:create', waitTTL: 5); // or -$id = $lock->lock('pdf:create', wait: new \DateInterval('PT5S')); +$id = $lock->lock('pdf:create', waitTTL: new \DateInterval('PT5S')); // Acquire lock with id - 14e1b600-9e97-11d8-9f32-f2801f1b9fd1 $id = $lock->lock('pdf:create', id: '14e1b600-9e97-11d8-9f32-f2801f1b9fd1'); @@ -70,8 +74,11 @@ $id = $lock->lock('pdf:create', id: '14e1b600-9e97-11d8-9f32-f2801f1b9fd1'); ### Acquire read lock Locks a resource for shared access, allowing multiple processes to access the resource simultaneously. When a resource -is locked for shared access, other processes that attempt to lock the resource for exclusive access will be blocked -until all shared locks are released. +is locked for shared access, other processes that attempt to lock the resource for exclusive access will fail to do so +while any shared lock is held. + +As with `lock()`, the `waitTTL` parameter is non-blocking by default (`false` is returned almost immediately, within +the server's `1ms` window); pass a positive `waitTTL` to block for up to that duration for the lock to become available. ```php $id = $lock->lockRead('pdf:create', ttl: 10); @@ -79,14 +86,29 @@ $id = $lock->lockRead('pdf:create', ttl: 10); $id = $lock->lockRead('pdf:create', ttl: new \DateInterval('PT10S')); // Acquire lock and wait 5 seconds until lock will be released -$id = $lock->lockRead('pdf:create', wait: 5); +$id = $lock->lockRead('pdf:create', waitTTL: 5); // or -$id = $lock->lockRead('pdf:create', wait: new \DateInterval('PT5S')); +$id = $lock->lockRead('pdf:create', waitTTL: new \DateInterval('PT5S')); // Acquire lock with id - 14e1b600-9e97-11d8-9f32-f2801f1b9fd1 $id = $lock->lockRead('pdf:create', id: '14e1b600-9e97-11d8-9f32-f2801f1b9fd1'); ``` +### Lock parameters + +Both `lock()` and `lockRead()` accept the same arguments: + +| Parameter | Type | Default | Description | +|------------|---------------------------------|---------------|-------------| +| `resource` | `non-empty-string` | — | Name of the resource to lock. | +| `id` | `non-empty-string`\|`null` | `null` | Lock owner id. When omitted a random UUID is generated. Keep it — the same `id` must be passed to `release()`. | +| `ttl` | `int`\|`float`\|`DateInterval` | `0` (forever) | Lock lifetime, in seconds. When it elapses the lock is released automatically; `0` means it never expires on its own. | +| `waitTTL` | `int`\|`float`\|`DateInterval` | `0` (~1ms) | How long to wait for the lock to become free, in seconds. `0` is effectively non-blocking — the server caps it at `1ms`, so `false` is returned almost immediately when the resource is already locked. A positive value blocks for up to that duration, then returns `false` on timeout. | + +Both methods return the lock **id** (`non-empty-string`) when the lock is acquired, or `false` when it is not (the resource stayed busy until the `waitTTL` window elapsed). + +> `ttl` and `waitTTL` are expressed in **seconds** (`int` or `float`), or as a `DateInterval`. + ### Release lock Releases an exclusive lock or read lock on a resource that was previously acquired by a call to `lock()` diff --git a/src/Lock.php b/src/Lock.php index a4757ad..2ef70d7 100644 --- a/src/Lock.php +++ b/src/Lock.php @@ -25,13 +25,19 @@ public function __construct( /** * Lock a resource for exclusive access * - * Locks a resource so that it can be accessed by one process at a time. When a resource is locked, - * other processes that attempt to lock the same resource will be blocked until the lock is released. + * Locks a resource so that it can be accessed by one process at a time. By default the call is non-blocking: + * if the resource is already locked, it returns false immediately. Pass a positive $waitTTL to wait for the + * lock to be released instead. * * @param non-empty-string $resource The name of the resource to be locked. * @param non-empty-string|null $id The lock ID. If not specified, a random UUID will be generated. * @param int|float|DateInterval $ttl The time-to-live of the lock, in seconds. Defaults to 0 (forever). - * @param int|float|DateInterval $waitTTL How long to wait to acquire lock until returning false. + * @param int|float|DateInterval $waitTTL How long to wait for the lock to become free before giving up, in seconds. + * Defaults to 0. With 0 the call is effectively non-blocking: the RoadRunner + * server caps the acquire window at defaultImmediateTimeout (1ms), so false + * is returned almost immediately when the resource is already locked. A + * positive value blocks for up to that duration, returning the lock id as + * soon as the lock is released, or false on timeout. * @return false|non-empty-string Returns lock ID if the lock was acquired successfully, false otherwise. * * @throws \InvalidArgumentException If ttl is negative. @@ -63,7 +69,12 @@ public function lock( * @param non-empty-string $resource The name of the resource to be locked. * @param non-empty-string|null $id The lock ID. If not specified, a random UUID will be generated. * @param int|float|DateInterval $ttl The time-to-live of the lock, in seconds. Defaults to 0 (forever). - * @param int|float|DateInterval $waitTTL How long to wait to acquire lock until returning false. + * @param int|float|DateInterval $waitTTL How long to wait for the lock to become free before giving up, in seconds. + * Defaults to 0. With 0 the call is effectively non-blocking: the RoadRunner + * server caps the acquire window at defaultImmediateTimeout (1ms), so false + * is returned almost immediately when the resource is already locked. A + * positive value blocks for up to that duration, returning the lock id as + * soon as the lock is released, or false on timeout. * @return false|non-empty-string Returns lock ID if the lock was acquired successfully, false otherwise. * * @throws \InvalidArgumentException If ttl is negative. diff --git a/src/LockInterface.php b/src/LockInterface.php index 8cad5a7..eefddde 100644 --- a/src/LockInterface.php +++ b/src/LockInterface.php @@ -9,13 +9,19 @@ interface LockInterface /** * Lock a resource for exclusive access. * - * Locks a resource so that it can be accessed by one process at a time. When a resource is locked, - * other processes that attempt to lock the same resource will be blocked until the lock is released. + * Locks a resource so that it can be accessed by one process at a time. By default the call is non-blocking: + * if the resource is already locked, it returns false immediately. Pass a positive $waitTTL to wait for the + * lock to be released instead. * * @param non-empty-string $resource The name of the resource to be locked. * @param non-empty-string|null $id The lock ID. If not specified, a random UUID will be generated. * @param int|float|\DateInterval $ttl The time-to-live of the lock, in seconds. Defaults to 0 (forever). - * @param int|float|\DateInterval $waitTTL How long to wait to acquire lock until returning false. + * @param int|float|\DateInterval $waitTTL How long to wait for the lock to become free before giving up, in seconds. + * Defaults to 0. With 0 the call is effectively non-blocking: the RoadRunner + * server caps the acquire window at defaultImmediateTimeout (1ms), so false + * is returned almost immediately when the resource is already locked. A + * positive value blocks for up to that duration, returning the lock id as + * soon as the lock is released, or false on timeout. * @return false|non-empty-string Returns lock ID if the lock was acquired successfully, false otherwise. */ public function lock( @@ -35,7 +41,12 @@ public function lock( * @param non-empty-string $resource The name of the resource to be locked. * @param non-empty-string|null $id The lock ID. If not specified, a random UUID will be generated. * @param int|float|\DateInterval $ttl The time-to-live of the lock, in seconds. Defaults to 0 (forever). - * @param int|float|\DateInterval $waitTTL How long to wait to acquire lock until returning false. + * @param int|float|\DateInterval $waitTTL How long to wait for the lock to become free before giving up, in seconds. + * Defaults to 0. With 0 the call is effectively non-blocking: the RoadRunner + * server caps the acquire window at defaultImmediateTimeout (1ms), so false + * is returned almost immediately when the resource is already locked. A + * positive value blocks for up to that duration, returning the lock id as + * soon as the lock is released, or false on timeout. * @return false|non-empty-string Returns lock ID if the lock was acquired successfully, false otherwise. */ public function lockRead(