# How to Add Delays or Timing Controls Before Step Execution in Probe

> Learn how to add delays and timing controls before step execution in Probe. Explore wait fields, retry initialDelay, and repeat interval for precise execution timing backed by Go timeDuration.

- Repository: [Tomohisa Oda/probe](https://github.com/linyows/probe)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Probe provides three distinct mechanisms—**`wait`**fields for pre-step pauses,**`retry.initialDelay`**for first-attempt delays, and job-level**`repeat.interval`**for timing between job runs—all backed by Go**`time.Duration`**parsing in the**`linyows/probe`**source code.**

When orchestrating complex workflows with Probe, controlling the timing of step execution is essential for rate limiting, service readiness, and resource management. The open-source `linyows/probe` repository implements granular timing controls through YAML configuration fields that integrate directly with the execution engine. These controls leverage Go's standard `time.Duration` parsing to support flexible duration specifications from milliseconds to minutes.

## Understanding Probe's Timing Control Mechanisms

Probe implements three distinct timing controls that operate at different stages of the execution lifecycle. Each mechanism serves a specific purpose, from pausing before individual actions to spacing out entire job repetitions.

The available controls include:

- **`wait` field** – Pauses execution immediately before a step's action runs
- **`retry.initialDelay`** – Delays the first retry attempt in a retry loop
- **`repeat.interval`** – Controls timing between successive job executions

All three mechanisms accept Go duration strings (e.g., `"500ms"`, `"2s"`, `"1m"`) and are implemented across [`step.go`](https://github.com/linyows/probe/blob/main/step.go) and [`executor.go`](https://github.com/linyows/probe/blob/main/executor.go) in the repository.

## Using the `wait` Field for Pre-Step Delays

The **`wait`** field defines a pause that occurs immediately before a step's action executes, following any skip checks but preceding the actual work. In [`step.go`](https://github.com/linyows/probe/blob/main/step.go), the `Step.handleWait` method parses this value and invokes `sleepWithMessage` to perform the delay.

Values less than one second trigger silent sleeping, while durations of one second or longer display a spinner suffix each second to maintain UI responsiveness. The implementation resides at lines 514–538 of [`step.go`](https://github.com/linyows/probe/blob/main/step.go).

```yaml
steps:
  - name: "Fetch data"
    uses: http
    with:
      url: https://api.example.com/data
    wait: "2s"   # pause 2 seconds before the HTTP request

```

For sub-second precision, specify milliseconds:

```yaml
steps:
  - name: "Health check"
    uses: http
    with:
      url: https://service/health
    wait: "500ms"   # silent 500ms pause

```

## Configuring `retry.initialDelay` for First-Attempt Timing

When implementing retry logic, the **`initialDelay`** field within a `retry` block specifies how long to wait before the first attempt executes. This differs from the standard `interval` field, which only controls delays between subsequent retries.

In [`step.go`](https://github.com/linyows/probe/blob/main/step.go) (lines 145–152), the `executeActionWithRetry` function explicitly honors `retry.InitialDelay.Duration` via `time.Sleep` before initiating the first action attempt.

```yaml
steps:
  - name: "Upload file"
    uses: sftp
    with:
      src: ./artifact.zip
      dst: /remote/path/
    retry:
      maxAttempts: 5
      interval: "3s"
      initialDelay: "10s"   # wait 10 seconds before the first attempt

```

This pattern proves particularly useful when connecting to services that require warm-up time or when avoiding thundering herd problems during batch operations.

## Job-Level Timing with `repeat.interval`

For workflows that require multiple executions of the same job sequence, the **`repeat.interval`** field controls the sleep duration between complete job runs. This top-level configuration affects the `Executor` rather than individual steps.

In [`executor.go`](https://github.com/linyows/probe/blob/main/executor.go) (lines 48–55), the `sleepBetweenRepeats` method checks the job's repeat counters and sleeps for `job.Repeat.Interval.Duration`, creating consistent pacing across job iterations.

```yaml
jobs:
  backup:
    repeat:
      total: 3
      interval: "1m30s"   # wait 90 seconds between each full backup run

    steps:
      - name: "Run backup"
        uses: script
        with:
          cmd: "./run-backup.sh"

```

## Combining Multiple Timing Controls

Probe allows simultaneous use of these timing mechanisms, creating layered execution control. When combining controls, the execution order follows the lifecycle: `wait` triggers first, then `initialDelay` (if retries are configured), followed by the action itself.

```yaml
steps:
  - name: "Run health check"
    uses: http
    with:
      url: https://service/health
    wait: "500ms"           # pre-step pause

    retry:
      maxAttempts: 3
      interval: "2s"        # between retries

      initialDelay: "5s"    # before first retry attempt

```

In this configuration, Probe waits 500 milliseconds before the initial HTTP request. If that request fails, it waits 5 seconds before the first retry, then 2 seconds between subsequent retries.

## Summary

- Probe provides three timing controls: **`wait`** fields on steps, **`retry.initialDelay`** for retry loops, and **`repeat.interval`** for job-level repetition.
- All duration values use Go's `time.Duration` parsing, supporting formats like `"500ms"`, `"3s"`, and `"2m"`.
- The **`wait`** field is processed in [`step.go`](https://github.com/linyows/probe/blob/main/step.go) by `handleWait` and `sleepWithMessage`, showing spinners for durations ≥1 second.
- **`retry.initialDelay`** is implemented in [`step.go`](https://github.com/linyows/probe/blob/main/step.go)'s `executeActionWithRetry` function (lines 145–152).
- **`repeat.interval`** is handled by [`executor.go`](https://github.com/linyows/probe/blob/main/executor.go)'s `sleepBetweenRepeats` method (lines 48–55).
- Values under one second sleep silently, while longer durations display progress indicators.

## Frequently Asked Questions

### What duration formats does Probe support for timing controls?

Probe accepts any valid Go `time.Duration` string, including `"500ms"` for milliseconds, `"3s"` for seconds, `"2m"` for minutes, and `"1h"` for hours. Legacy integer values like `"5"` are interpreted as seconds. All parsing uses Go's standard library duration parsing functions.

### Where is the `wait` field processed in the Probe source code?

The `wait` field is processed in [`step.go`](https://github.com/linyows/probe/blob/main/step.go) within the `Step.handleWait` method (lines 514–538). This method parses the duration string and calls `sleepWithMessage`, which either sleeps silently for sub-second durations or displays a spinner suffix for each second of longer waits.

### How does Probe handle waits longer than one second?

When the `wait` duration equals or exceeds one second, the `sleepWithMessage` function in [`step.go`](https://github.com/linyows/probe/blob/main/step.go) prints a spinner suffix to the console each second during the pause. This keeps the terminal UI responsive and indicates that the process is actively waiting rather than frozen.

### Can I use both `wait` and `retry.initialDelay` in the same step?

Yes, these fields are complementary. The `wait` field executes immediately before the step's first action attempt, while `retry.initialDelay` only applies if the step fails and enters the retry loop. If both are configured, Probe executes the `wait` delay first, attempts the action, and then applies `initialDelay` before the first retry attempt.