diff --git a/docs/Tutorials/Schedules.md b/docs/Tutorials/Schedules.md index e660bfeb8..d6864eac3 100644 --- a/docs/Tutorials/Schedules.md +++ b/docs/Tutorials/Schedules.md @@ -1,6 +1,6 @@ # Schedules -A Schedule in Pode is a long-running async task, and unlike timers, when they trigger they are run in their own separate runspace - so they don't affect each other if they take a while to process. +A Schedule in Pode is a long-running async task, and unlike timers, when they trigger they are run in their own separate runspace - so they don't affect each other if they take a while to process. By default up to a maximum of 10 schedules can run concurrently, this can be changed by using the [`Set-PodeScheduleConcurrency`](../../Functions/Core/Set-PodeScheduleConcurrency) function. Schedule triggers are defined using [`cron expressions`](../Misc/CronExpressions), basic syntax is supported as well as some predefined expressions. Schedules can start immediately, have a delayed start time, and also have a defined end time. diff --git a/examples/schedules-long-running.ps1 b/examples/schedules-long-running.ps1 new file mode 100644 index 000000000..37c0fb8b3 --- /dev/null +++ b/examples/schedules-long-running.ps1 @@ -0,0 +1,26 @@ +$path = Split-Path -Parent -Path (Split-Path -Parent -Path $MyInvocation.MyCommand.Path) +Import-Module "$($path)/src/Pode.psm1" -Force -ErrorAction Stop + +# or just: +# Import-Module Pode + +# create a server, and start listening on port 8085 +Start-PodeServer { + + # listen on localhost:8085 + Add-PodeEndpoint -Address * -Port 8085 -Protocol Http + + # add lots of schedules that each sleep for a while + 1..30 | ForEach-Object { + Add-PodeSchedule -Name "Schedule_$($_)" -Cron '@minutely' -ArgumentList @{ ID = $_ } -ScriptBlock { + param($ID) + + $seconds = (Get-Random -Minimum 5 -Maximum 40) + Start-Sleep -Seconds $seconds + "ID: $($ID) [$($seconds)]" | Out-PodeHost + } + } + + Set-PodeScheduleConcurrency -Maximum 30 + +} \ No newline at end of file diff --git a/src/Pode.psd1 b/src/Pode.psd1 index 412e4611e..0882bf20d 100644 --- a/src/Pode.psd1 +++ b/src/Pode.psd1 @@ -125,6 +125,7 @@ 'Clear-PodeSchedule', 'Invoke-PodeSchedule', 'Edit-PodeSchedule', + 'Set-PodeScheduleConcurrency', # timers 'Add-PodeTimer', diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index 257e2c2b1..d1e3c0c92 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -265,7 +265,7 @@ function New-PodeRunspacePools $PodeContext.RunspacePools.Signals.Open() # setup schedule runspace pool - $PodeContext.RunspacePools.Schedules = [runspacefactory]::CreateRunspacePool(1, 2, $PodeContext.RunspaceState, $Host) + $PodeContext.RunspacePools.Schedules = [runspacefactory]::CreateRunspacePool(1, 10, $PodeContext.RunspaceState, $Host) $PodeContext.RunspacePools.Schedules.Open() # setup gui runspace pool (only for non-ps-core) diff --git a/src/Private/Server.ps1 b/src/Private/Server.ps1 index 9940e84f8..c7a79fdae 100644 --- a/src/Private/Server.ps1 +++ b/src/Private/Server.ps1 @@ -16,6 +16,9 @@ function Start-PodeInternalServer # create the shared runspace state New-PodeRunspaceState + # start the runspace pools for web, schedules, etc + New-PodeRunspacePools + # get the server's script and invoke it - to set up routes, timers, middleware, etc $_script = $PodeContext.Server.Logic if (Test-PodePath -Path $PodeContext.Server.LogicPath -NoStatus) { @@ -24,9 +27,6 @@ function Start-PodeInternalServer Invoke-PodeScriptBlock -ScriptBlock $_script -NoNewClosure - # start the runspace pools for web, schedules, etc - New-PodeRunspacePools - # create timer/schedules for auto-restarting New-PodeAutoRestartServer diff --git a/src/Public/Core.ps1 b/src/Public/Core.ps1 index 6193cb89a..07c3d0ca3 100644 --- a/src/Public/Core.ps1 +++ b/src/Public/Core.ps1 @@ -1068,6 +1068,43 @@ function Add-PodeSchedule } } +<# +.SYNOPSIS +Set the maximum number of concurrent schedules. + +.DESCRIPTION +Set the maximum number of concurrent schedules. + +.PARAMETER Maximum +The Maximum number of schdules to run. + +.EXAMPLE +Set-PodeScheduleConcurrency -Maximum 25 +#> +function Set-PodeScheduleConcurrency +{ + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [int] + $Maximum + ) + + # error if <=0 + if ($Maximum -le 0) { + throw "Maximum concurrent schedules must be >=0 but got: $($Maximum)" + } + + # ensure max > min + $_min = $PodeContext.RunspacePools.Schedules.GetMinRunspaces() + if ($_min -gt $Maximum) { + throw "Maximum concurrent schedules cannot be less than the minimum of $($_min) but got: $($Maximum)" + } + + # set the max schedules + $PodeContext.RunspacePools.Schedules.SetMaxRunspaces($Maximum) +} + <# .SYNOPSIS Adhoc invoke a Schedule's logic.