Summary
When a Pode Task throws, its process is set to Failed. The task housekeeper then immediately closes and removes that process if Retry.Max is 0 (the default from Add-PodeTask).
That makes it easy to miss Failed processes in Get-PodeTaskProcess / a custom dispatcher. Completed processes stay around for one minute. Failed processes with default retry settings may disappear on the next housekeeper tick (~20 seconds), or even sooner relative to a polling timer.
This behaviour is present in v2.12.1 and still in v2.13.4 (src/Private/Tasks.ps1).
Expected behaviour
One of:
- Failed processes are retained for a short window (similar to Completed, e.g. 1 minute) so callers can inspect
State, Exception, and then call Close-PodeTask.
- If immediate removal is intentional, the docs for Tasks /
Add-PodeTask -MaxRetries should say so clearly: default MaxRetries 0 means a Failed process is eligible for deletion as soon as the housekeeper runs.
Actual behaviour
Housekeeper logic (simplified):
if ($process.State -ieq 'Failed') {
if ($process.Retry.Count -ge $task.Retry.Max) {
Close-PodeTaskInternal -Process $process
continue
}
if (!$task.Retry.AutoRetry) {
continue
}
# ... auto-retry ...
}
On first failure:
$process.Retry.Count is 0
$task.Retry.Max defaults to 0
0 -ge 0 is $true → process is closed and removed
There is no 1-minute grace period for Failed (that delay exists only for Completed).
AutoRetry is never reached in the default case, because the process is already removed.
Reproduction
Add-PodeTask -Name 'Example' -ScriptBlock { throw 'boom' }
# later
Invoke-PodeTask -Name 'Example'
# poll every 2s
Get-PodeTaskProcess -Name 'Example'
Often the process never appears as Failed (or only for a very short time). A dispatcher that only handles State -in ('Completed','Failed') can miss the failure entirely.
Workaround
Register the task with:
Add-PodeTask -Name 'Example' -ScriptBlock { throw 'boom' } -MaxRetries 1
# do NOT pass -AutoRetry
Then:
Retry.Count (0) is not >= Retry.Max (1)
AutoRetry is $false, so the housekeeper continues
- the Failed process stays until the app calls
Close-PodeTask
This is an undocumented side effect of the retry counter, not a documented “retain Failed processes” feature.
Suggested fix
Any of these would help:
- Docs: state that
MaxRetries 0 (default) causes Failed processes to be removed by the housekeeper immediately; document the -MaxRetries 1 (no -AutoRetry) retain pattern if that is supported.
- Behaviour: do not treat “no retries configured” as “delete immediately”. e.g. only auto-remove Failed processes after the same 1-minute window as Completed, or only when
AutoRetry is set and retries are exhausted.
- Align Failed cleanup with Completed: keep the process until
CompletedTime.AddMinutes(1).
Option 2/3 would be safer for anyone polling Get-PodeTaskProcess without using -Wait on Invoke-PodeTask.
Environment
- Pode 2.12.1 (also verified against 2.13.4 source)
- PowerShell 7.x
- Windows
- Async
Invoke-PodeTask + periodic Get-PodeTaskProcess (timer), not Wait-PodeTask
Summary
When a Pode Task throws, its process is set to
Failed. The task housekeeper then immediately closes and removes that process ifRetry.Maxis0(the default fromAdd-PodeTask).That makes it easy to miss
Failedprocesses inGet-PodeTaskProcess/ a custom dispatcher. Completed processes stay around for one minute. Failed processes with default retry settings may disappear on the next housekeeper tick (~20 seconds), or even sooner relative to a polling timer.This behaviour is present in v2.12.1 and still in v2.13.4 (
src/Private/Tasks.ps1).Expected behaviour
One of:
State,Exception, and then callClose-PodeTask.Add-PodeTask -MaxRetriesshould say so clearly: defaultMaxRetries 0means a Failed process is eligible for deletion as soon as the housekeeper runs.Actual behaviour
Housekeeper logic (simplified):
On first failure:
$process.Retry.Countis0$task.Retry.Maxdefaults to00 -ge 0is$true→ process is closed and removedThere is no 1-minute grace period for
Failed(that delay exists only forCompleted).AutoRetryis never reached in the default case, because the process is already removed.Reproduction
Often the process never appears as
Failed(or only for a very short time). A dispatcher that only handlesState -in ('Completed','Failed')can miss the failure entirely.Workaround
Register the task with:
Then:
Retry.Count(0) is not>= Retry.Max(1)AutoRetryis$false, so the housekeepercontinuesClose-PodeTaskThis is an undocumented side effect of the retry counter, not a documented “retain Failed processes” feature.
Suggested fix
Any of these would help:
MaxRetries 0(default) causes Failed processes to be removed by the housekeeper immediately; document the-MaxRetries 1(no-AutoRetry) retain pattern if that is supported.AutoRetryis set and retries are exhausted.CompletedTime.AddMinutes(1).Option 2/3 would be safer for anyone polling
Get-PodeTaskProcesswithout using-WaitonInvoke-PodeTask.Environment
Invoke-PodeTask+ periodicGet-PodeTaskProcess(timer), notWait-PodeTask