How to Repeat Jobs at Intervals in Probe: A Complete Guide to Workflow Automation
Probe supports repeating jobs at configurable intervals using the repeat block in workflow YAML, allowing you to run steps multiple times with delays between executions or in parallel for load testing.
The linyows/probe repository provides a flexible job repetition system built around three core components: the Repeat struct for configuration, the Executor for orchestration, and the Job definition for context propagation. This guide explains how to configure interval-based repetition, choose between synchronous and asynchronous execution modes, and leverage template variables for dynamic workflows.
Understanding the Repeat Block Structure
The Repeat Struct and Validation
In repeat.go (lines 99-104), the Repeat struct defines the configuration schema:
type Repeat struct {
Count int
Interval Interval
Async bool
}
The system validates the count field against PROBE_MAX_REPEAT_COUNT, which defaults to 10,000. If you attempt to configure a count exceeding this limit, the validator in repeat.go (lines 106-113) returns an error indicating the environment variable name for adjustment.
Interval Parsing and Formats
The Interval type in repeat.go (lines 42-86) accepts multiple formats:
- Integer values: Interpreted as seconds (e.g.,
30equals 30 seconds) - Duration strings: Standard Go duration formats like
30s,1m,2m30s
During YAML unmarshaling, the UnmarshalYAML method automatically detects the format and converts it to a time.Duration for internal use.
Synchronous vs Asynchronous Execution
The Executor in executor.go implements two distinct execution strategies based on the async flag.
Synchronous Mode (Default)
When async: false (the default), executeJobRepeatLoop in executor.go (lines 82-97) runs jobs sequentially:
- Executes
Job.Startfor the current iteration - Checks
JobScheduler.ShouldRepeatJob(jobID)to determine continuation - Calls
sleepBetweenRepeats(lines 48-55) to executetime.Sleep(e.job.Repeat.Interval.Duration)between iterations
This mode ensures that each repetition completes before the next begins, making it ideal for health checks or sequential monitoring tasks.
Asynchronous Mode for Concurrent Testing
When async: true, executeJobRepeatLoopAsync in executor.go (lines 101-145) enables parallel execution:
- Creates a
time.NewTickerusing the configured interval - Spawns a goroutine for each iteration immediately
- Uses the ticker to space out the goroutine launches
- Tracks overall success using
atomic.Bool
This mode is specifically designed for load testing scenarios where you need overlapping job executions to simulate concurrent user traffic or stress test services.
Practical Configuration Examples
Basic Health Check with Intervals
Configure a job to check service health three times with five-second pauses:
jobs:
health-check:
name: "Check service health"
repeat:
count: 3
interval: 5s
steps:
- name: "curl health endpoint"
run: curl -f http://localhost/health
The job executes sequentially, waiting five seconds between each curl command.
Load Testing with Async Repetition
Simulate concurrent load by running four overlapping instances with two-second spacing:
jobs:
stress-test:
name: "Load test"
repeat:
count: 4
interval: 2s
async: true
steps:
- name: "Run load test"
run: ./load-test --duration=30s
Four goroutines execute simultaneously, each starting two seconds after the previous, creating overlapping load test windows.
Accessing the Repeat Index in Steps
Use the {{repeat_index}} template variable to access the current iteration number (1-based):
jobs:
numbered:
repeat:
count: 3
interval: 1s
steps:
- name: "Echo iteration"
run: echo "Processing iteration {{repeat_index}}"
Output:
Processing iteration 1
Processing iteration 2
Processing iteration 3
The Job struct in job.go (lines 14-15) provides context fields IsRepeating, RepeatCurrent, and RepeatTotal that enable this template resolution.
Configuration Limits and Environment Variables
Probe enforces safety limits through environment variables defined in repeat.go:
| Variable | Default | Purpose |
|---|---|---|
PROBE_MAX_REPEAT_COUNT |
10000 | Maximum allowed value for repeat.count |
PROBE_MAX_ATTEMPTS |
10000 | Maximum retry attempts for step-level retries |
To run a job more than 10,000 times, override the limit before execution:
export PROBE_MAX_REPEAT_COUNT=50000
probe run my-workflow.yml
The validator in repeat.go (lines 106-113) references the environment variable name in error messages when limits are exceeded.
Summary
- Repeat configuration uses the
repeatblock withcount,interval, and optionalasyncfields in workflow YAML - Synchronous mode (default) runs jobs sequentially with
time.Sleepbetween iterations, implemented inexecutor.golines 82-97 - Asynchronous mode spawns goroutines with a ticker for concurrent execution, implemented in
executor.golines 101-145 - Template variable
{{repeat_index}}provides access to the current iteration number via context fields injob.go - Safety limits default to 10,000 repetitions, configurable via
PROBE_MAX_REPEAT_COUNTenvironment variable
Frequently Asked Questions
What is the maximum number of times a job can repeat in Probe?
By default, Probe limits job repetition to 10,000 executions. This limit is enforced by the validator in repeat.go and can be increased by setting the PROBE_MAX_REPEAT_COUNT environment variable to a higher value before running the workflow.
How does Probe handle the interval between repeated job executions?
Probe supports two execution modes. In synchronous mode (the default), the executor uses time.Sleep with the specified duration between sequential runs. In asynchronous mode, the executor creates a time.NewTicker to space out goroutine launches, allowing jobs to overlap while maintaining the interval between starts.
Can I access the current repetition number within job steps?
Yes. Probe exposes the current iteration through the {{repeat_index}} template variable, which resolves to a 1-based index. This functionality is powered by context fields (IsRepeating, RepeatCurrent, RepeatTotal) defined in the Job struct in job.go, allowing steps to vary behavior based on the repetition count.
When should I use asynchronous repetition instead of synchronous repetition?
Use asynchronous repetition (async: true) when you need concurrent job execution for load testing or stress testing scenarios where overlapping runs simulate real-world traffic patterns. Use synchronous repetition for sequential monitoring, health checks, or any scenario where you need the previous execution to complete before the next begins.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →