diff --git a/examples/Tasks.ps1 b/examples/Tasks.ps1 index 9b98e730a..def36c56b 100644 --- a/examples/Tasks.ps1 +++ b/examples/Tasks.ps1 @@ -53,6 +53,8 @@ Start-PodeServer { Add-PodeTask -Name 'Test2' -ScriptBlock { param($value) Start-Sleep -Seconds 10 + "a $($value) is comming" | Out-Default + Start-Sleep -Seconds 100 "a $($value) is never late, it arrives exactly when it means to" | Out-Default } diff --git a/examples/Web-Dump.ps1 b/examples/Web-Dump.ps1 index 6fc3cf9ef..67b7809ac 100644 --- a/examples/Web-Dump.ps1 +++ b/examples/Web-Dump.ps1 @@ -14,7 +14,7 @@ http://localhost:8081/openapi Documentation: http://localhost:8081/docs - +5 .LINK https://github.com/Badgerati/Pode/blob/develop/examples/Web-Dump.ps1 @@ -39,7 +39,7 @@ try { catch { throw } # Start Pode server with specified script block -Start-PodeServer -Threads 4 -ScriptBlock { +Start-PodeServer -Threads 4 -EnablePool Tasks -ScriptBlock { # listen on localhost:8081 Add-PodeEndpoint -Address localhost -Port 8081 -Protocol Http @@ -94,7 +94,12 @@ Start-PodeServer -Threads 4 -ScriptBlock { } } | Set-PodeOARouteInfo -Summary 'Dump state' -Description 'Dump the memory state of the server.' -Tags 'dump' -OperationId 'dump'-PassThru | Set-PodeOARequest -Parameters (New-PodeOAStringProperty -Name 'format' -Description 'Dump export format.' -Enum 'json', 'clixml', 'txt', 'bin', 'yaml' -Default 'json' | ConvertTo-PodeOAParameter -In Query ) - } + + Add-PodeRoute -Method Get -Path '/task/async' -PassThru -ScriptBlock { + Invoke-PodeTask -Name 'Test' -ArgumentList @{ value = 'wizard' } | Out-Null + Write-PodeJsonResponse -Value @{ Result = 'jobs done' } + }| Set-PodeOARouteInfo -Summary 'Task' + } Add-PodeVerb -Verb 'HELLO' -ScriptBlock { Write-PodeTcpClient -Message 'HI' @@ -148,4 +153,15 @@ Start-PodeServer -Threads 4 -ScriptBlock { $name = Read-PodeTcpClient -CRLFMessageEnd Write-PodeTcpClient -Message "Hi, $($name)!" } + + + Add-PodeTask -Name 'Test' -ScriptBlock { + param($value) + Start-PodeSleep -Seconds 10 + "a $($value) is comming" | Out-Default + Start-PodeSleep -Seconds 100 + "a $($value) is never late, it arrives exactly when it means to" | Out-Default + } + + } \ No newline at end of file diff --git a/src/Private/Dump.ps1 b/src/Private/Dump.ps1 index c53b0dfbc..34c4e0239 100644 --- a/src/Private/Dump.ps1 +++ b/src/Private/Dump.ps1 @@ -155,7 +155,11 @@ function Invoke-PodeDumpInternal { # Retrieve all runspaces related to Pode ordered by name $runspaces = Get-Runspace | Where-Object { $_.Name -like 'Pode_*' -and ` - $_.Name -notlike '*__pode_session_inmem_cleanup__*' } | Sort-Object Name + $_.Name -notlike '*__pode_session_inmem_cleanup__*' -and ` + $_.Name -notlike 'Pode_*_Listener_*' -and ` + $_.Name -notlike 'Pode_*_KeepAlive_*' -and ` + $_.Name -notlike 'Pode_Signals_Broadcaster_*' + } | Sort-Object Name $runspaceDetails = @{} @@ -234,8 +238,8 @@ function Invoke-PodeDumpInternal { Write-PodeHost -ForegroundColor Yellow "Memory dump saved to $dumpFilePath" } end { - - Reset-PodeCancellationToken -Type 'Dump' + Reset-PodeCancellationToken -Type Cancellation + Reset-PodeCancellationToken -Type Dump } } @@ -287,25 +291,33 @@ function Get-PodeRunspaceVariablesViaDebugger { # Initialize variables collection $variables = @(@{}) + for ($i = 0; $i -le 3; $i++) { try { - # Attach the debugger and break all + + # Wait for the event to be triggered or timeout + Write-PodeHost "Waiting for $($Runspace.Name) to enter in debug ." -NoNewLine + $debugger = [Pode.Embedded.DebuggerHandler]::new($Runspace) Enable-RunspaceDebug -BreakAll -Runspace $Runspace # Wait for the event to be triggered or timeout + $startTime = [DateTime]::UtcNow + Start-Sleep -Milliseconds 500 - Write-PodeHost "Waiting for $($Runspace.Name) to enter in debug ." -NoNewLine + Write-PodeHost '.' -NoNewLine - # Suspend the runspace - if (Suspend-PodeRunspace -Runspace $Runspace) { - # Retrieve and output the collected variables from the embedded C# code - $variables = $debugger.Variables - break + while (!$debugger.IsEventTriggered) { + Start-Sleep -Milliseconds 1000 + Write-PodeHost '.' -NoNewLine + if (([DateTime]::UtcNow - $startTime).TotalSeconds -ge $Timeout) { + Write-PodeHost "Failed (Timeout reached after $Timeout seconds.)" + return $variables[0] + } } - + return $debugger.Variables } catch { # Log the error details using Write-PodeErrorLog. @@ -710,23 +722,26 @@ function Suspend-PodeRunspace { param ( $Runspace ) + # Attach the debugger and break all $debugger = [Pode.Embedded.DebuggerHandler]::new($Runspace) Enable-RunspaceDebug -BreakAll -Runspace $Runspace + # Start-Sleep -Milliseconds 500 + # Enable-RunspaceDebug -BreakAll -Runspace $Runspace # Wait for the event to be triggered or timeout $startTime = [DateTime]::UtcNow - Start-Sleep -Milliseconds 1000 + Start-Sleep -Milliseconds 500 # Write-PodeHost '..' -NoNewLine - # Send-PodeInterrupt -Name $Runspace.Name + #Send-PodeInterrupt -Name $Runspace.Name Write-PodeHost '.' -NoNewLine while (!$debugger.IsEventTriggered) { Start-Sleep -Milliseconds 1000 - if (([int]([DateTime]::UtcNow - $startTime).TotalSeconds) % 5 -eq 0) { + <# if (([int]([DateTime]::UtcNow - $startTime).TotalSeconds) % 5 -eq 0) { if (Send-PodeInterrupt -Name $Runspace.Name) { Write-PodeHost '*' -NoNewLine } @@ -736,7 +751,8 @@ function Suspend-PodeRunspace { } else { Write-PodeHost '.' -NoNewLine - } + }#> + Write-PodeHost '.' -NoNewLine if (([DateTime]::UtcNow - $startTime).TotalSeconds -ge $Timeout) { Write-PodeHost "Failed (Timeout reached after $Timeout seconds.)" return $false diff --git a/src/Private/FileWatchers.ps1 b/src/Private/FileWatchers.ps1 index ce0ebc4c7..2299e0d27 100644 --- a/src/Private/FileWatchers.ps1 +++ b/src/Private/FileWatchers.ps1 @@ -62,7 +62,13 @@ function Start-PodeFileWatcherRunspace { ) try { - while ($Watcher.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Watcher.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } $evt = (Wait-PodeTask -Task $Watcher.GetFileEventAsync($PodeContext.Tokens.Cancellation.Token)) try { @@ -144,7 +150,13 @@ function Start-PodeFileWatcherRunspace { ) try { - while ($Watcher.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Watcher.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } Start-Sleep -Seconds 1 } } diff --git a/src/Private/Gui.ps1 b/src/Private/Gui.ps1 index 94b772795..506e35b93 100644 --- a/src/Private/Gui.ps1 +++ b/src/Private/Gui.ps1 @@ -27,7 +27,7 @@ function Start-PodeGuiRunspace { # poll the server for a response $count = 0 - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while (!$PodeContext.Tokens.Terminate.IsCancellationRequested) { try { $null = Invoke-WebRequest -Method Get -Uri $uri -UseBasicParsing -ErrorAction Stop if (!$?) { diff --git a/src/Private/Logging.ps1 b/src/Private/Logging.ps1 index e2c11f81c..b79694031 100644 --- a/src/Private/Logging.ps1 +++ b/src/Private/Logging.ps1 @@ -376,7 +376,13 @@ function Start-PodeLoggingRunspace { $script = { try { - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while (!$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } try { # if there are no logs to process, just sleep for a few seconds - but after checking the batch if ($PodeContext.LogsToProcess.Count -eq 0) { diff --git a/src/Private/PodeServer.ps1 b/src/Private/PodeServer.ps1 index d0f725fca..67c6e655b 100644 --- a/src/Private/PodeServer.ps1 +++ b/src/Private/PodeServer.ps1 @@ -129,7 +129,13 @@ function Start-PodeWebServer { ) try { - while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Listener.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } # get request and response $context = (Wait-PodeTask -Task $Listener.GetContextAsync($PodeContext.Tokens.Cancellation.Token)) @@ -307,7 +313,13 @@ function Start-PodeWebServer { ) try { - while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Listener.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } $message = (Wait-PodeTask -Task $Listener.GetServerSignalAsync($PodeContext.Tokens.Cancellation.Token)) try { @@ -385,7 +397,13 @@ function Start-PodeWebServer { ) try { - while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Listener.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } $context = (Wait-PodeTask -Task $Listener.GetClientSignalAsync($PodeContext.Tokens.Cancellation.Token)) try { @@ -464,7 +482,13 @@ function Start-PodeWebServer { ) try { - while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Listener.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } Start-Sleep -Seconds 1 } } diff --git a/src/Private/Schedules.ps1 b/src/Private/Schedules.ps1 index 007f45140..4af978667 100644 --- a/src/Private/Schedules.ps1 +++ b/src/Private/Schedules.ps1 @@ -66,7 +66,13 @@ function Start-PodeScheduleRunspace { # first, sleep for a period of time to get to 00 seconds (start of minute) Start-Sleep -Seconds (60 - [DateTime]::Now.Second) - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while (!$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ( $PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } try { $_now = [DateTime]::Now @@ -95,7 +101,8 @@ function Start-PodeScheduleRunspace { # Loop in 5-second intervals until the remaining seconds are covered while ($remainingSeconds -gt 0) { $sleepTime = [math]::Min(5, $remainingSeconds) # Sleep for 5 seconds or remaining time - Start-Sleep -Seconds $sleepTime + # Start-Sleep -Seconds $sleepTime + Start-PodeSleep -Seconds $sleepTime $remainingSeconds -= $sleepTime } } diff --git a/src/Private/ServiceServer.ps1 b/src/Private/ServiceServer.ps1 index bd7fe6eca..35d934576 100644 --- a/src/Private/ServiceServer.ps1 +++ b/src/Private/ServiceServer.ps1 @@ -13,7 +13,7 @@ function Start-PodeServiceServer { $serverScript = { try { - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while (!$PodeContext.Tokens.Terminate.IsCancellationRequested) { # the event object $script:ServiceEvent = @{ Lockable = $PodeContext.Threading.Lockables.Global diff --git a/src/Private/SmtpServer.ps1 b/src/Private/SmtpServer.ps1 index c3cc7cfd2..ba2e08e37 100644 --- a/src/Private/SmtpServer.ps1 +++ b/src/Private/SmtpServer.ps1 @@ -90,7 +90,13 @@ function Start-PodeSmtpServer { ) try { - while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Listener.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } # get email $context = (Wait-PodeTask -Task $Listener.GetContextAsync($PodeContext.Tokens.Cancellation.Token)) @@ -189,7 +195,13 @@ function Start-PodeSmtpServer { ) try { - while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Listener.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ( $PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } Start-Sleep -Seconds 1 } } diff --git a/src/Private/TcpServer.ps1 b/src/Private/TcpServer.ps1 index 43a3c38c5..dc41f67ae 100644 --- a/src/Private/TcpServer.ps1 +++ b/src/Private/TcpServer.ps1 @@ -86,7 +86,13 @@ function Start-PodeTcpServer { ) try { - while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Listener.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ( $PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } # get email $context = (Wait-PodeTask -Task $Listener.GetContextAsync($PodeContext.Tokens.Cancellation.Token)) @@ -207,7 +213,13 @@ function Start-PodeTcpServer { ) try { - while ($Listener.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Listener.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ( $PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } Start-Sleep -Seconds 1 } } diff --git a/src/Private/Timers.ps1 b/src/Private/Timers.ps1 index 48b19ba9a..f6bbd032c 100644 --- a/src/Private/Timers.ps1 +++ b/src/Private/Timers.ps1 @@ -21,7 +21,13 @@ function Start-PodeTimerRunspace { $script = { try { - while (!$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while (!$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ($PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } try { $_now = [DateTime]::Now diff --git a/src/Private/WebSockets.ps1 b/src/Private/WebSockets.ps1 index b1c0cdc8f..1d82ee09d 100644 --- a/src/Private/WebSockets.ps1 +++ b/src/Private/WebSockets.ps1 @@ -52,7 +52,15 @@ function Start-PodeWebSocketRunspace { ) try { - while ($Receiver.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Receiver.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + + while ( $PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + write-podehost 'checking for PodeContext.Tokens.Dump.IsCancellationRequested' + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } # get request $request = (Wait-PodeTask -Task $Receiver.GetWebSocketRequestAsync($PodeContext.Tokens.Cancellation.Token)) @@ -119,9 +127,18 @@ function Start-PodeWebSocketRunspace { ) try { - while ($Receiver.IsConnected -and !$PodeContext.Tokens.Cancellation.IsCancellationRequested) { + while ($Receiver.IsConnected -and !$PodeContext.Tokens.Terminate.IsCancellationRequested) { + while ( $PodeContext.Tokens.Suspend.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } + write-podehost 'checking for PodeContext.Tokens.Dump.IsCancellationRequested' + while ($PodeContext.Tokens.Dump.IsCancellationRequested) { + Start-Sleep -Seconds 1 + } Start-Sleep -Seconds 1 } + + } catch [System.OperationCanceledException] { $_ | Write-PodeErrorLog -Level Debug diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 0d2e5e78d..79563a305 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -231,7 +231,7 @@ function Start-PodeServer { } # sit here waiting for termination/cancellation, or to restart the server - while ( !($PodeContext.Tokens.Cancellation.IsCancellationRequested)) { + while ( !($PodeContext.Tokens.Terminate.IsCancellationRequested)) { Start-Sleep -Seconds 1 if (!$PodeContext.Server.Console.DisableConsoleInput) { @@ -247,6 +247,7 @@ function Start-PodeServer { if (($PodeContext.Tokens.Dump.IsCancellationRequested) -or (Test-PodeDumpPressed -Key $key) ) { Clear-PodeKeyPressed + Invoke-PodeDump Invoke-PodeDumpInternal -Format $PodeContext.Server.Debug.Dump.Format -Path $PodeContext.Server.Debug.Dump.Path -MaxDepth $PodeContext.Server.Debug.Dump.MaxDepth } @@ -405,6 +406,7 @@ function Resume-PodeServer { param() if ( $PodeContext.Server.Suspended) { $PodeContext.Tokens.Resume.Cancel() + $PodeContext.Tokens.Cancellation.Cancel() } } @@ -426,8 +428,8 @@ function Suspend-PodeServer { [CmdletBinding()] param() if (! $PodeContext.Server.Suspended) { + $PodeContext.Tokens.Cancellation.Cancel() $PodeContext.Tokens.Suspend.Cancel() - #$PodeContext.Tokens.Cancellation.Cancel() } } diff --git a/src/Public/Utilities.ps1 b/src/Public/Utilities.ps1 index 9e6171bcd..f89340c58 100644 --- a/src/Public/Utilities.ps1 +++ b/src/Public/Utilities.ps1 @@ -1553,4 +1553,45 @@ function Invoke-PodeDump { ) $PodeContext.Server.Debug.Dump.Param = $PSBoundParameters $PodeContext.Tokens.Dump.Cancel() -} \ No newline at end of file + $PodeContext.Tokens.Cancellation.Cancel() +} + + + +function Start-PodeSleep { + [CmdletBinding()] + param ( + [Parameter(Position = 0, Mandatory = $false, ParameterSetName = 'Seconds')] + [int]$Seconds = 1, + + [Parameter(Position = 0, Mandatory = $false, ParameterSetName = 'Milliseconds')] + [int]$Milliseconds, + + [Parameter(Position = 0, Mandatory = $false, ParameterSetName = 'Duration')] + [TimeSpan]$Duration + ) + + # Determine end time based on the parameter set + switch ($PSCmdlet.ParameterSetName) { + 'Seconds' { + $endTime = (Get-Date).AddSeconds($Seconds) + } + 'Milliseconds' { + $endTime = (Get-Date).AddMilliseconds($Milliseconds) + } + 'Duration' { + $endTime = (Get-Date).Add($Duration) + } + } + + while ((Get-Date) -lt $endTime) { + # Check if a debugger is attached + # if ($Host.Debugger.IsActive) { + # Write-PodeHost "Debugger is attached. Waiting for interaction..." + # Debugger # Trigger a breakpoint to allow interaction + # } + + # Sleep for a short duration to prevent high CPU usage + Start-Sleep -Milliseconds 200 + } +}