Skip to content

Retry

If you want to retry a task that had failed a couple of times more, you can use the retry property in the Task.

v3.4.0 #303

Example

You can find the related examples here.

Usage

ts
import { delay, Listr } from 'listr2'

interface Ctx {
  output: string
}

const tasks = new Listr<Ctx>(
  [
    {
      title: 'Some type errors',
      task: async(_, task): Promise<void> => {
        await delay(1000)
        task.output = 'test'

        await delay(1000)
        throw new Error('This type can not be assigned to type with, oh noes')
      },
      retry: 3
    }
  ],
  {
    concurrent: false,
    exitOnError: true
  }
)

const context = await tasks.run()

Retry Delay

v6.0.0 #668

Retry action can have a delay between the tries. For enabling this behavior, you can pass the retry to the given task as an object.

ts
import { delay, Listr } from 'listr2'

interface Ctx {
  output: string
}

const tasks = new Listr<Ctx>(
  [
    {
      title: 'Some type errors',
      task: async(_, task): Promise<void> => {
        await delay(1000)
        task.output = 'test'

        await delay(1000)
        throw new Error('This type can not be assigned to type with, oh noes')
      },
      retry: {
        delay: 1000,
        tries: 3
      }
    }
  ],
  {
    concurrent: false,
    exitOnError: true
  }
)

const context = await tasks.run()

While waiting between attempts the task enters a paused state, and the DefaultRenderer shows a live countdown until the next try through its pausedTimer option. You can check for this state inside a task with task.isPaused().

Retry Event

Retrying is self-aware, and you can access the task if it is retrying via task.isRetrying(). It will either return an object with the given interface where the count will be 0 for not repeating tasks, and error is the last encountered error if retrying.

Retry Count

ts
import { delay, Listr } from 'listr2'

const tasks = new Listr(
  [
    {
      title: 'Some thing with errors',
      task: async(_, task): Promise<void> => {
        const retry = task.isRetrying()

        if (retry.count > 0) {
          task.title = 'This means I am retrying.'
          task.output = ['I am self aware that I am retrying for the %dth time.', retry.count]
        }

        await delay(1000)
        throw new Error('This type can not be assigned to type with, oh noes')
      },
      retry: 3
    }
  ],
  { exitOnError: false }
)

await tasks.run()

Last Error

ts
import { delay, Listr } from 'listr2'

const tasks = new Listr(
  [
    {
      title: 'Some thing with errors',
      task: async(_, task): Promise<void> => {
        const retry = task.isRetrying()

        if (retry.count > 0) {
          // eslint-disable-next-line no-constant-binary-expression
          if (retry.error === new Error('Something')) {
            task.title = 'I will process the task further.'
          }
        }

        await delay(1000)
        throw new Error('This type can not be assigned to type with, oh noes')
      },
      retry: 3
    }
  ],
  { exitOnError: false }
)

await tasks.run()

Renderer

  • When retrying, the task title will be reset to the original task title.

DefaultRenderer

Details

suffixRetries?

optional suffixRetries?: boolean

Defined in: packages/listr2/src/renderer/default/renderer.interface.ts:139

Suffix retry messages to clearly indicate the task is currently retrying.

  • true will add [RETRY:COUNT] as a suffix.
  • false will not add a suffix.

Default Value

false


pausedTimer?

optional pausedTimer?: PresetTimer

Defined in: packages/listr2/src/renderer/default/renderer.interface.ts:148

Show duration for the pauses.

Default Value

PRESET_TIMER

SimpleRenderer & VerboseRenderer

The non-TTY renderers log a RETRY entry with the current attempt count on each retry, rather than resetting an in-place title.