Skip to content

Failed task processes are removed immediately when MaxRetries is 0 (default) #1766

Description

@Artyum

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:

  1. 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.
  2. 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:

  1. 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.
  2. 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.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions