Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions app-runner/Private/DeviceLockManager.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,35 @@ function Request-DeviceAccess {
# try to create the same mutex concurrently with initial ownership.
$createdNew = $false
$mutex = $null
$maxAttempts = 3
$attempt = 0

try {
# Try to open existing mutex first
$mutex = [System.Threading.Mutex]::OpenExisting($mutexName)
Write-Debug "Opened existing mutex: $mutexName"
} catch [System.Threading.WaitHandleCannotBeOpenedException] {
# Mutex doesn't exist yet, create it without requesting initial ownership
# We'll acquire it separately with WaitOne() to handle race conditions properly
Write-Debug "Mutex doesn't exist, creating: $mutexName"
$mutex = New-Object System.Threading.Mutex($false, $mutexName, [ref]$createdNew)
Write-Debug "Created new mutex: $mutexName (createdNew: $createdNew)"
} catch [System.UnauthorizedAccessException] {
throw "Access denied when accessing mutex '$mutexName'. This may require elevated privileges. Error: $($_.Exception.Message)"
} catch {
throw "Failed to open or create mutex '$mutexName': $($_.Exception.Message)"
while ($attempt -lt $maxAttempts -and -not $mutex) {
$attempt++

try {
# Try to open existing mutex first
$mutex = [System.Threading.Mutex]::OpenExisting($mutexName)
Write-Debug "Opened existing mutex: $mutexName (attempt $attempt)"
} catch [System.Threading.WaitHandleCannotBeOpenedException] {
# Mutex doesn't exist yet, try to create it without requesting initial ownership
# We'll acquire it separately with WaitOne() to handle race conditions properly
Write-Debug "Mutex doesn't exist, creating: $mutexName (attempt $attempt)"
$mutex = New-Object System.Threading.Mutex($false, $mutexName, [ref]$createdNew)
Write-Debug "Created new mutex: $mutexName (createdNew: $createdNew)"
} catch [System.UnauthorizedAccessException] {
# Race condition: another process created the mutex between our OpenExisting and New-Object calls
# This can happen during creation or when opening, retry in both cases
if ($attempt -lt $maxAttempts) {
Write-Debug "UnauthorizedAccessException on attempt $attempt - another process likely created mutex, retrying..."
Start-Sleep -Milliseconds 50
continue
} else {
throw "Access denied when accessing mutex '$mutexName' after $maxAttempts attempts. This may require elevated privileges. Error: $($_.Exception.Message)"
}
} catch {
throw "Failed to open or create mutex '$mutexName': $($_.Exception.Message)"
}
}

# Now acquire the mutex (whether we just created it or opened existing)
Expand Down
12 changes: 7 additions & 5 deletions app-runner/Private/DeviceProviders/DeviceProvider.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class DeviceProvider {
[int]$MaxRetryAttempts = 2
[bool]$IsRebooting = $false # Internal flag to skip retry-on-timeout during reboot

[string]$DebugOutputForwarder = "ForEach-Object { (`$_ | Out-String).Trim() } | Where-Object { `$_.Length -gt 0 } | Tee-Object -variable capturedOutput | Foreach-Object { Write-Debug `$_ } ; `$capturedOutput"

DeviceProvider() {
$this.Commands = @{}
$this.Timeouts = @{}
Expand Down Expand Up @@ -91,7 +93,7 @@ class DeviceProvider {
}

# Start job with the provided scriptblock and arguments
$job = Start-Job -ScriptBlock $scriptBlock -ArgumentList $platform, $action, $command
$job = Start-Job -ScriptBlock $scriptBlock -ArgumentList $platform, $action, $command, $this.DebugOutputForwarder

# Wait with progress messages every 30 seconds
$waitIntervalSeconds = 30
Expand Down Expand Up @@ -182,11 +184,11 @@ class DeviceProvider {

# Build the execution scriptblock once - used for both timeout and non-timeout paths
$scriptBlock = {
param($platform, $act, $cmd)
param($platform, $act, $cmd, $debugForwarder)
try {
$PSNativeCommandUseErrorActionPreference = $false
Write-Debug "${platform}: Invoking ($act) command $cmd"
$result = Invoke-Expression "$cmd | Tee-Object -variable capturedOutput | Foreach-Object { Write-Debug `$_ } ; `$capturedOutput"
$result = Invoke-Expression "$cmd | $debugForwarder"
if ($LASTEXITCODE -ne 0) {
Write-Warning "Command ($act`: $cmd) failed with exit code $($LASTEXITCODE) $($result.Length -gt 0 ? 'and output:' : '')"
$result | ForEach-Object { Write-Warning $_ }
Expand Down Expand Up @@ -217,7 +219,7 @@ class DeviceProvider {
}

# Otherwise, execute directly without timeout
return & $scriptBlock $this.Platform $action $command
return & $scriptBlock $this.Platform $action $command $this.DebugOutputForwarder
}

[hashtable] CreateSessionInfo() {
Expand Down Expand Up @@ -316,7 +318,7 @@ class DeviceProvider {
$startDate = Get-Date
try {
$PSNativeCommandUseErrorActionPreference = $false
$result = Invoke-Expression "$command | Tee-Object -variable capturedOutput | Foreach-Object { Write-Debug `$_ } ; `$capturedOutput"
$result = Invoke-Expression "$command | $($this.DebugOutputForwarder)"
$exitCode = $LASTEXITCODE
} finally {
$PSNativeCommandUseErrorActionPreference = $true
Expand Down
27 changes: 9 additions & 18 deletions sentry-api-client/Public/Find-SentryEventByTag.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
function Find-SentryEventByTag
{
function Find-SentryEventByTag {
<#
.SYNOPSIS
Finds issues and their associated events filtered by a tag.
Expand Down Expand Up @@ -65,8 +64,7 @@ function Find-SentryEventByTag
sort = $Sort
}

if ($Cursor)
{
if ($Cursor) {
$QueryParams.cursor = $Cursor
}

Expand All @@ -79,20 +77,17 @@ function Find-SentryEventByTag
$Issues = if ($Response -is [Array]) { $Response } else { @($Response) }
$AllEvents = @()

Write-Debug "Found $($Issues.Count) issues matching tag '$TagName`:$TagValue'. Fetching events..."
Write-Debug "Found $(@($Issues).Count) issues matching tag '$TagName`:$TagValue'. Fetching events..."

foreach ($Issue in $Issues)
{
try
{
foreach ($Issue in @($Issues)) {
try {
# Use the organization issues events endpoint with tag filtering
$EventsQueryParams = @{
query = $QueryString
full = $true
}

if ($Limit)
{
if ($Limit) {
# Distribute limit across issues, minimum 1 per issue
$EventsPerIssue = [Math]::Max(1, [Math]::Floor($Limit / $Issues.Count))
$EventsQueryParams.limit = $EventsPerIssue
Expand All @@ -102,19 +97,15 @@ function Find-SentryEventByTag
$EventsUri = Get-SentryOrganizationUrl -Resource "issues/$($Issue.id)/events/" -QueryString $EventsQueryStringParams

$IssueEvents = Invoke-SentryApiRequest -Uri $EventsUri -Method 'GET'
$IssueEventsArray = if ($IssueEvents -is [Array]) { $IssueEvents } else { @($IssueEvents) }
Write-Debug "Found $($IssueEvents.Count) events for issue $($Issue.id) matching tag '$TagName`:$TagValue', fetching actual event content."
Write-Debug "Found $(@($IssueEvents).Count) events for issue $($Issue.id) matching tag '$TagName`:$TagValue', fetching actual event content."

# The response from the API above differs from the Get-SentryEvent so we just grab event IDs and fetch directly.
foreach ($_event in $IssueEventsArray)
{
foreach ($_event in @($IssueEvents)) {
$_event = Get-SentryEvent -EventId $_event.eventID
$AllEvents += $_event
}

}
catch
{
} catch {
Write-Error "Failed to retrieve events for issue $($Issue.id): $_"
}
}
Expand Down