| | | 1 | | <# |
| | | 2 | | .SYNOPSIS |
| | | 3 | | Executes a script block while holding a named lock to ensure exclusive access to a resource. |
| | | 4 | | .DESCRIPTION |
| | | 5 | | The Use-KrLock function allows you to execute a script block while holding a lock associated with a specified key. |
| | | 6 | | This is useful for synchronizing access to shared resources within the current application instance. |
| | | 7 | | The function retrieves a lock object using the lock registry and attempts to acquire the lock before executing the s |
| | | 8 | | If a timeout is specified and the lock cannot be acquired within that time frame, an error is thrown. |
| | | 9 | | After the script block is executed, the lock is released in a finally block to ensure that it happens even if an err |
| | | 10 | | .PARAMETER Key |
| | | 11 | | The unique identifier for the lock. This key is used to retrieve the corresponding lock object from the lock registr |
| | | 12 | | If a lock object does not already exist for this key, a new one will be created. The key should be a string that uni |
| | | 13 | | section that the lock is intended to protect. It is important to use consistent keys across the application to ensur |
| | | 14 | | .PARAMETER ScriptBlock |
| | | 15 | | The script block to execute while holding the lock. This is the code that will be run with exclusive access to the r |
| | | 16 | | The script block can contain any valid PowerShell code and can utilize the protected resource safely, knowing that i |
| | | 17 | | .PARAMETER TimeoutMilliseconds |
| | | 18 | | The maximum time in milliseconds to wait for the lock before timing out. The default value is -1, which means to wai |
| | | 19 | | If a positive value is specified and the lock cannot be acquired within that time frame, an error will be thrown. |
| | | 20 | | This parameter allows you to control how long the function should wait for the lock, which can be useful in scenario |
| | | 21 | | indefinitely and prefer to handle lock acquisition failures gracefully. |
| | | 22 | | .EXAMPLE |
| | | 23 | | Use-KrLock -Key "MyResourceLock" -ScriptBlock { |
| | | 24 | | # Code to execute while holding the lock |
| | | 25 | | Write-Host "This code is running with exclusive access to MyResourceLock." |
| | | 26 | | } |
| | | 27 | | This example demonstrates how to use the Use-KrLock function to execute a script block while holding a lock associat |
| | | 28 | | The code within the script block will have exclusive access to the resource protected by "MyResourceLock", ensuring |
| | | 29 | | .NOTES |
| | | 30 | | This function is part of the Kestrun framework and is used to manage locks for synchronizing access to shared resour |
| | | 31 | | It relies on a lock registry to store and retrieve lock objects based on their associated keys. |
| | | 32 | | The locks returned by this function can be used in conjunction with synchronization primitives such as Monitor, Mute |
| | | 33 | | Semaphore to control access to critical sections of code or shared resources in a thread-safe manner. |
| | | 34 | | It is important to ensure that the keys used with this function are consistent and unique to avoid unintended lockin |
| | | 35 | | Additionally, proper handling of lock acquisition and release is crucial to prevent deadlocks and ensure the smooth |
| | | 36 | | #> |
| | | 37 | | function Use-KrLock { |
| | | 38 | | [KestrunRuntimeApi('Everywhere')] |
| | | 39 | | [CmdletBinding()] |
| | | 40 | | param( |
| | | 41 | | [Parameter(Mandatory = $true, Position = 0)] |
| | | 42 | | [ValidateNotNullOrEmpty()] |
| | | 43 | | [string]$Key, |
| | | 44 | | |
| | | 45 | | [Parameter(Mandatory = $true, Position = 1)] |
| | | 46 | | [scriptblock]$ScriptBlock, |
| | | 47 | | |
| | | 48 | | [Parameter()] |
| | | 49 | | [int]$TimeoutMilliseconds = -1 |
| | | 50 | | ) |
| | | 51 | | |
| | 1 | 52 | | $lock = [Kestrun.Utilities.KestrunLockRegistry]::GetOrCreate($Key) |
| | | 53 | | |
| | 1 | 54 | | $acquired = $false |
| | | 55 | | |
| | | 56 | | try { |
| | 1 | 57 | | if ($TimeoutMilliseconds -lt 0) { |
| | 1 | 58 | | $lock.Wait() |
| | 1 | 59 | | $acquired = $true |
| | | 60 | | } else { |
| | 1 | 61 | | $acquired = $lock.Wait($TimeoutMilliseconds) |
| | 1 | 62 | | if (-not $acquired) { |
| | 1 | 63 | | throw "Timeout acquiring lock '$Key'" |
| | | 64 | | } |
| | | 65 | | } |
| | | 66 | | |
| | 1 | 67 | | return & $ScriptBlock |
| | | 68 | | } finally { |
| | 1 | 69 | | if ($acquired) { |
| | | 70 | | try { |
| | 1 | 71 | | $null = $lock.Release() |
| | | 72 | | } catch { |
| | 0 | 73 | | Write-KrLog -Level Verbose -Message "Failed to release mutex '{Key}'" -Values $Key -Exception $_ |
| | | 74 | | } |
| | | 75 | | } |
| | | 76 | | } |
| | | 77 | | } |