The Retry Step in Jenkins
Some failures are just bad luck. Learn how the Jenkins retry step gives a pipeline a second chance, when that is wise, when it is dangerous, and how to design retries that make builds calmer instead of noisier.
You press the button on a coffee machine and nothing happens. You press it again, and the coffee flows. The machine was not broken. A tiny hiccup got in the way, and a second try solved it. Now imagine the machine is out of beans. Pressing the button ten more times will not help, and it may even damage the motor.
Software pipelines live with the same two kinds of trouble. Downloading a package can fail because the network blinked for one second. Compiling code can fail because a developer wrote a bug. The first kind deserves a retry. The second kind deserves a fix. The Jenkins retry step is the tool that presses the button again, and the skill lies in knowing when pressing is wise.
In this guide you will learn what the retry step does, how it counts attempts, how to combine it with timeouts and waiting, which failures to retry and which to leave alone, how it affects cost and safety, and which mistakes cause the most trouble. We assume you know nothing about Jenkins yet, and we explain each new word the first time it appears.
1What Is the Retry Step?
The retry step runs a piece of your pipeline again when it fails, up to a number of times that you choose.
First, the basics
Jenkins is a free automation server that builds, tests, and delivers software. A pipeline is a written list of steps that Jenkins follows, stored in a text file called a Jenkinsfile. A step is one action in that list, such as “download the dependencies” or “run the tests.” When a step fails, the pipeline normally stops, marks the build as failed, and tells the team.
What retry adds
The retry step is a wrapper. You put other steps inside it, and you tell it how many attempts are allowed. If the steps inside succeed, the pipeline moves on. If they fail, the retry step runs them again from the beginning. Only when the last allowed attempt fails does the failure escape and stop the pipeline.
The key word is “transient”
A transient failure is a problem that goes away by itself, such as a brief network outage, a busy server, or a temporary lock. A permanent failure is a problem that stays until someone fixes it, such as a syntax error or a wrong password. Retry is a good answer for the first kind and a poor answer for the second.
Think of calling a friend and getting a busy signal. Calling again a minute later is sensible, because the line will probably be free. Calling a number that has been disconnected, ten times in a row, is pointless. The retry step is the redial button, and good judgement decides when to press it.
What it gives you
- Fewer false alarms: one-second glitches no longer turn a build red.
- Less human effort: nobody has to click “rebuild” and wait again.
- Steadier pipelines: builds that depend on many outside systems become far more dependable.
Retry does not fix problems. It waits for problems to go away. If the cause is permanent, retry only makes the failure slower and more expensive.
2Why It Exists: The Problem and the History
Modern builds depend on dozens of outside systems, and outside systems occasionally stumble.
The old world
In the early days of automation, a build usually ran on one machine and used files that were already there. There was little to go wrong. As software grew, builds began to download libraries from the internet, pull container images from registries, talk to cloud services, and reach test databases. Every one of those connections is a small chance of failure.
The mathematics of many small risks
Suppose each outside call succeeds 99.5 times out of 100. That sounds excellent. But a pipeline with fifty such calls succeeds every time only about 78 times out of 100. In other words, more than one build in five fails for reasons that have nothing to do with the code. Teams call this build noise, and it slowly destroys trust: people start ignoring red builds.
The Pipeline answer
When Jenkins moved to Pipeline as code around 2016, the community added a small set of control-flow steps, and retry was among the first. It was intentionally simple: run this block again if it fails. Over the years, it has gained refinements, such as the ability to retry only for certain kinds of infrastructure trouble, like the loss of a build machine.
Without retry
- Every network blink turns a build red.
- People click “rebuild” by hand, again and again.
- Real failures hide among false alarms.
With sensible retry
- Short glitches heal themselves.
- Red builds mean something again.
- Engineers spend time on real problems.
A postal worker who finds nobody at home tries again later that day. Nobody would call that a failure of the postal system. Retrying is a normal part of any service that depends on other people or machines being ready.
Real-world motivation
Large technology companies that publish about reliability engineering describe retries as a basic building block of distributed systems, from web browsers to cloud storage clients. Build pipelines are distributed systems too, so the same lessons apply, including the warning that careless retries can cause more harm than the failures they hide.
3Core Concepts: The Words You Must Know
A handful of ideas explain almost everything about retrying well.
Attempt
One run of the wrapped steps. The first run counts as attempt one, so a limit of three means one original try and at most two retries.
Transient failure
A problem that disappears on its own, such as a brief network error or a busy server. Good candidates for retry.
Permanent failure
A problem that stays until fixed, such as a compile error or a wrong password. Retrying it wastes time.
Idempotent
An action that is safe to repeat, because doing it twice leaves the same result as doing it once. Retry is safest around idempotent actions.
Backoff
Waiting between attempts, often for longer each time. It gives a struggling service room to recover.
Jitter
A small random change to the waiting time, so that many clients do not all retry at exactly the same moment.
Timeout
A maximum time for an attempt. Without it, a hung attempt never ends, and the retry never gets its turn.
Retry condition
A test that decides whether a failure is worth retrying, such as “only when the build machine was lost.”
Vocabulary table
| Word | Meaning | Example |
|---|---|---|
| Exception | The signal a failing step raises to say something went wrong | A download step reports a connection error |
| Flaky test | A test that sometimes passes and sometimes fails on the same code | A timing-dependent web test |
| Rate limit | A server’s cap on how many requests a client may make | A registry answering “too many requests” |
| Retry storm | Many clients retrying at once and overwhelming a recovering service | Fifty builds all re-pulling an image together |
| Circuit breaker | A rule that stops trying a service that keeps failing | Skip the mirror after five straight failures |
The retry step does not itself wait between attempts. If you want a pause, you add one yourself. This is one of the most important facts in the whole guide, and later chapters show how to handle it.
4Architecture and Where Retry Sits
Retry is not a service or a plugin you install. It is a shape you give to a part of your pipeline.
The layers of a pipeline
A pipeline is made of stages, which are named phases such as “Build” and “Test.” Each stage holds steps. A wrapper step, like retry or timeout, holds other steps inside it. Wrappers can be placed inside each other, like nesting dolls. The order of the dolls changes the meaning.
flowchart TD
P["Pipeline"] --> S["Stage Fetch Dependencies"]
S --> R["Retry Wrapper with limit of 3 attempts"]
R --> T["Timeout Wrapper for each attempt"]
T --> B["Body Steps such as download command"]
B -->|"Succeeds"| OK["Stage continues"]
B -->|"Fails and attempts remain"| R
B -->|"Fails on last attempt"| F["Failure reaches the stage"]
F --> PF["Stage fails and build is marked failed"]
Reading the diagram
The stage contains a retry wrapper. Inside the retry sits a timeout, so every attempt gets its own time limit. Inside the timeout are the real steps. If the steps succeed, the stage continues. If they fail and attempts remain, control returns to the retry wrapper, which starts another attempt. Only when the final attempt fails does the failure travel outward to the stage, which fails, and the build is marked as failed.
Four places to use retry
| Place | What is retried | Typical use |
|---|---|---|
| Around one small step | Only that step | A single download or upload |
| Around a group of steps | The group, from its beginning | Fetch, unpack, and verify as a unit |
| As a stage option | The whole stage | A whole deployment check stage |
| As a pipeline option | The entire pipeline | Rarely wise, because everything runs again |
Picture a cook making a sauce. If it splashes on the counter, they wipe up and stir again (retry one small step). If the whole pot burns, they must start the entire sauce over (retry a group). Sending the whole restaurant back to opening time (retry the pipeline) is almost never the right response.
Keep the wrapped area small
The smaller the retried block, the cheaper each retry is, and the fewer side effects can repeat. Wrap the one flaky action, not the whole stage that happens to contain it.
5How the Retry Step Works Internally
There is no magic here. The rules are few, and knowing them prevents most surprises.
Rule one: the count includes the first attempt
When you write a limit of three, the wrapped steps run at most three times in total. That is the original try plus up to two retries. Many beginners assume that three means “the first try plus three more,” which leads to confusion when they count attempts in the log.
Rule two: the body restarts from the top
Each attempt runs the entire wrapped block again from its first step. If the block has five steps and the fifth fails, all five run again. That is why small blocks are better than large ones: they repeat less work, and they repeat less that could be harmful to repeat.
Rule three: a failure is an exception
Inside Jenkins, a failing step raises an exception, a signal that says “something went wrong.” The retry wrapper catches it and decides whether to try again. A command that exits with a non-zero result also becomes such a failure, because the shell step turns it into one.
Rule four: a person aborting is not retried
If a human presses the abort button, retry does not fight it. The abort is respected, and the build stops. This is the correct behaviour, and it means retry cannot trap a build in a loop that people cannot escape.
Rule five: the final failure escapes
If the last allowed attempt fails, the failure propagates outward, exactly as if there had been no retry. The stage fails, and the build is marked failed. The log shows the earlier failures too, so you can see what happened.
Rule six: nothing is cleaned automatically
Retry does not clean the workspace, delete half-written files, stop leftover containers, or undo side effects. Whatever the failed attempt left behind is still there when the next attempt starts. Cleaning up is your job, and later chapters show how.
A retry that starts with a half-finished mess from the previous attempt can fail for a new reason, and the log then shows a confusing second error instead of the original one. Always think about what the first failure leaves behind.
If a child knocks over a tower of blocks and you say “try again,” the blocks are still scattered on the floor. A sensible parent sweeps them together before the next attempt. Retry says “try again,” but it never sweeps the floor.
Count includes attempt one
A limit of three means three runs in total.
Whole block repeats
Every attempt starts at the block’s first step.
Aborts are respected
A person can always stop the build.
No automatic cleanup
Leftovers from failed attempts remain for the next one.
6Data Flow and Lifecycle of a Retried Step
Follow one flaky download through three attempts and see what the pipeline does at every moment.
sequenceDiagram
participant PL as Pipeline
participant RT as Retry Wrapper
participant BD as Body Steps
participant SV as Remote Server
PL->>RT: Enter block with limit 3
RT->>BD: Attempt 1
BD->>SV: Request package
SV-->>BD: Connection reset
BD-->>RT: Failure raised
RT->>RT: Attempts remain so run again
RT->>BD: Attempt 2
BD->>SV: Request package
SV-->>BD: Server busy
BD-->>RT: Failure raised
RT->>BD: Attempt 3
BD->>SV: Request package
SV-->>BD: Package delivered
BD-->>RT: Success
RT-->>PL: Block completes and pipeline continues
The lifecycle in plain steps
Enter
The pipeline reaches the retry block. The wrapper notes the limit and starts the first attempt.
Run
The body steps execute. They may talk to servers, files, or tools.
Fail or succeed
If everything passes, the wrapper finishes and the pipeline moves on. If a step raises an exception, the wrapper catches it.
Decide
The wrapper checks whether attempts remain, whether the failure was a human abort, and whether any retry conditions apply.
Repeat
If a retry is allowed, the body starts again from its first step, immediately, unless you added a wait.
Finish
Either an attempt succeeds, or the last attempt fails and the failure escapes to the stage.
What the log looks like
The build log shows each attempt as a separate stretch of output, with the failure message at the end of each. The wrapper also prints a short note that it is retrying and how many attempts remain. When you investigate a strange build, read all the attempts, because the first failure usually holds the real cause.
Time adds up
Three attempts of ten minutes each mean thirty minutes of waiting before the pipeline can fail. Always think about the worst case, not just the lucky case.
Print a short line at the start of the block, such as “Downloading dependencies, up to 3 attempts.” When someone reads the log at night, they immediately understand why the same lines appear more than once.
7The Ways to Write a Retry
Jenkins offers several places to put a retry. Each has a different reach.
The step form
The most common form is the retry step itself. You write its name, give it a number in brackets, and place the steps you want repeated inside braces after it. It works in both Declarative and Scripted pipelines, and it can be placed anywhere a step can go, including inside a stage, a parallel branch, or another wrapper.
The stage option
In Declarative Pipeline, a stage can carry an options section, and one of the available options is retry. Setting it tells Jenkins to run the entire stage again when the stage fails. This is convenient, but it repeats everything in the stage, including steps that were fine.
The pipeline option
The same option can be placed at the top of the pipeline, which retries the whole pipeline. This is rarely a good idea. A full pipeline can take an hour, and repeating it because of one blink in the last minute is wasteful.
The conditions form
Newer versions of the step accept a count together with a list of conditions, so it retries only for certain kinds of failure. Conditions are covered in their own chapter.
| Form | Reach | Strength | Weakness |
|---|---|---|---|
| Step around a small block | Just that block | Precise and cheap | You must place it yourself |
| Step with conditions | Just that block, only for chosen failures | Avoids retrying real bugs | Needs a recent Jenkins version |
| Stage option | The whole stage | Easy to switch on | Repeats successful work too |
| Pipeline option | The whole pipeline | One line | Slow and costly, rarely advisable |
A helpful rule
Use the smallest form that solves your problem. Prefer a step around one flaky action to a stage option, and prefer a stage option to a pipeline option.
If a single bolt on a car is stuck, you try the bolt again. You do not disassemble the whole car and rebuild it from the factory floor. Choosing the size of the retry is choosing how much of the car you take apart.
A retry option on a stage that contains deployment steps can deploy twice. Before you add a stage-wide retry, read every step in the stage and ask what happens if it runs again.
8What to Retry, and What to Leave Alone
This is the most valuable chapter in the guide. A retry on the wrong failure hides bugs and wastes money.
flowchart TD
F["A step failed"] --> Q1{"Is the cause outside your code"}
Q1 -->|"No, a bug or bad config"| N1["Do not retry. Fix the cause"]
Q1 -->|"Yes"| Q2{"Is it likely to pass on a later try"}
Q2 -->|"No, such as wrong password"| N2["Do not retry. Report clearly"]
Q2 -->|"Yes, such as timeout or busy server"| Q3{"Is the action safe to repeat"}
Q3 -->|"No, it changes real data"| N3["Make it idempotent first or do not retry"]
Q3 -->|"Yes"| Y["Retry with a limit, a timeout and a wait"]
Good candidates
| Failure | Why it is transient |
|---|---|
| Network timeout or connection reset | Networks blink and recover |
| Server busy or temporary error from a service | Load passes |
| Rate limit answer | The limit resets after a short time (wait before retrying) |
| Registry or package mirror hiccup | Mirrors restart or catch up |
| Build machine lost during a step | A new machine can be assigned |
| Short-lived lock on a shared resource | The lock is released soon |
| Cloud resource still being created | It becomes ready after a moment |
Poor candidates
| Failure | Why retry does not help |
|---|---|
| Compile or syntax error | The code is wrong every time |
| Test assertion failure | The behaviour is wrong, not unlucky |
| Wrong or expired credentials | The password stays wrong, and repeated attempts can lock the account |
| Missing file or wrong path | Configuration mistakes do not heal |
| Permission denied | Rules do not change between attempts |
| Invalid input rejected by a service | The same input is rejected again |
The safe-to-repeat question
Even a transient failure needs one more check: can the action run twice without harm? Downloading a file twice is harmless. Charging a customer twice is not. If an action changes real data and is not idempotent, retry may do damage, and the action needs redesign first.
If an elevator door fails to open, pressing the button again is fine. If an ATM freezes halfway through handing out cash, pressing “withdraw” again could take money twice. Some actions are safe to repeat, and some are not, and you must know which one you hold.
Keep a short list of the failures your team has genuinely seen and decided are transient, with the log text that identifies each. It turns retry from guesswork into policy.
9Retry Conditions: Retrying Only the Right Failures
Newer versions of the retry step can filter failures, so real bugs are not retried.
The problem with blanket retry
A plain retry treats every failure the same. A network blink and a compile error both trigger another attempt. The compile error will fail again, three times, and the team waits for no benefit.
The conditions idea
The step can be given a list of conditions together with its count. When conditions are given, the wrapper retries only if the failure matches one of them. Otherwise, the failure escapes immediately. Check the documentation for your Jenkins version, because the exact names and behaviour depend on the Pipeline plugin versions installed.
Conditions you may meet
Agent lost
Matches when the build machine disconnected or disappeared during the block. A new machine can pick up the work, so a retry is sensible.
Non-resumable
Matches when a step cannot resume after the Jenkins controller restarted. Retrying lets the block start fresh.
Kubernetes agent lost
Matches when a container-based agent was removed, for example by the cluster reclaiming resources. Provided by the Kubernetes plugin.
Custom conditions
When built-in conditions do not fit, teams write their own logic that inspects the failure and decides.
Infrastructure versus application failures
A helpful way to think: conditions such as agent loss describe infrastructure failures, where the work itself was fine but the place it ran vanished. Those are almost always worth retrying. Application failures, where the work itself went wrong, usually are not.
Benefits of conditions
- Real bugs fail fast instead of after three attempts.
- Infrastructure trouble still heals itself.
- The policy is visible in the code.
Limits
- Requires recent plugin versions.
- Built-in conditions cover infrastructure, not network errors inside your commands.
- Custom logic needs care and tests.
A delivery company re-sends a parcel if the van broke down, because the parcel is fine. It does not re-send a parcel addressed to a house that does not exist. Conditions let you tell those two situations apart.
Test how conditions behave on your own Jenkins before relying on them. A plain retry and a conditional retry treat ordinary command failures differently, and mixing them up can leave you with no retry at all when you expected one.
10Retry Together with Timeout
A retry without a timeout is a trap. A hung attempt never fails, so the retry never gets to act.
The hung attempt problem
Retry reacts to failures. But some problems do not fail. They hang. A download that connects and then sends nothing can wait for hours. To the retry wrapper, the attempt is still in progress, so nothing is retried, and an agent stays busy for no reason.
The timeout wrapper
The timeout step sets a maximum time for the steps inside it. When the time is up, Jenkins stops the block and raises a failure. Placed inside the retry, the timeout gives every attempt its own limit, so a hung attempt is cut off, and the retry can try again.
Inside or outside?
| Arrangement | Meaning | When to use it |
|---|---|---|
| Timeout inside retry | Each attempt has its own time limit | Guarding against hung attempts |
| Timeout outside retry | One time limit for all attempts together | Capping the total time a block may consume |
| Both | A limit per attempt and a limit for the whole block | Strict budgets in critical pipelines |
Choosing the numbers
Set the per-attempt timeout to a comfortable multiple of the normal duration. If a download normally takes thirty seconds, five minutes is generous and still catches a hang. Set the outer limit so that the whole worst case still fits your patience: three attempts of five minutes plus waiting is about seventeen minutes.
Check your version’s behaviour
How a timeout interacts with retry can differ between Jenkins and plugin versions, especially about whether a timeout counts as a retryable failure. Always test it once with a deliberately hanging command in a safe job, and write down what happens.
A teacher who says “you may redo the test up to three times” but never ends a test period would find students staring at page one all afternoon. A time limit per attempt turns “try again” into something that can actually happen.
Whenever you write a retry around anything that touches the network, write a timeout right inside it in the same edit. Treat them as a pair.
11Waiting Between Attempts: Backoff and Jitter
Retrying instantly is often useless. If a server is overloaded, hitting it again a millisecond later just adds to the pile.
No built-in wait
The retry step starts the next attempt immediately. If you want a pause, you put a sleep step into the block, usually at the start of attempts after the first. Since the step does not tell the block which attempt it is on in most versions, people keep their own counter or write a small loop when they need growing waits.
Kinds of waiting
Constant delay
Wait the same time before every retry, for example ten seconds. Simple and good enough for many cases.
Exponential backoff
Wait longer each time, such as 5, 10, 20, then 40 seconds. Gives a struggling service progressively more room to recover.
Jitter
Add a small random amount to each wait. Without it, fifty builds that failed together retry together and fail together again.
Maximum delay
Limit the longest wait, so that backoff never grows into half an hour of idle time.
The retry storm
Imagine a package registry that hiccups for two seconds. Two hundred builds hit the error at once. All of them retry after exactly five seconds, and the registry, still recovering, receives two hundred requests in the same instant and fails again. This is a retry storm. Jitter spreads the retries out, and backoff thins them out over time.
Waiting for a condition instead
Sometimes you are not retrying a failure, but waiting for something to become ready, such as a newly created service. Jenkins has a waitUntil step that repeats a block until it returns true, with growing pauses between checks. It fits “wait for readiness” better than retry, which fits “repeat after failure.”
| Need | Best tool |
|---|---|
| Repeat an action that sometimes fails | Retry with a wait |
| Wait until a service is ready | waitUntil with a timeout |
| Pause for a fixed time | sleep |
| Different treatment by error type | Retry with conditions, or a small custom loop |
When a busy restaurant tells you there is a wait, you do not knock on the door every second. You come back in ten minutes. A hundred people all returning at exactly the same minute would create a new queue, so sensible guests come back at slightly different times. That is backoff with jitter.
12Retry Compared with Its Neighbours
Jenkins offers several ways to deal with failure. Picking the right one avoids a lot of confusion.
| Tool | What it does | Best for |
|---|---|---|
| retry step | Repeats a block of steps after failure, up to a limit | Transient failures in a specific action |
| timeout step | Stops a block that takes too long | Hung actions, budgets on time |
| waitUntil step | Repeats a check until it returns true | Waiting for readiness |
| sleep step | Pauses for a fixed time | Simple delays, backoff pieces |
| try and catch | Handles a failure with your own logic | Custom recovery, cleanup, or alternate paths |
| catchError | Marks the build or stage result but lets the pipeline continue | Non-critical steps that must not stop everything |
| post section | Runs actions after a stage or build, depending on the result | Notifications and cleanup |
| Tool’s own retry option | Many command-line tools can retry internally | Downloads and network calls, precisely tuned |
| Naginator plugin | Reruns a whole build after failure | Legacy jobs, full-build flakiness |
| Restart from stage | A person restarts a Declarative pipeline from a chosen stage | Manual recovery after a real fix |
When the tool’s own retry is better
Many command-line tools can retry by themselves. A download tool such as curl can repeat a request several times with waits, and package managers have settings for retries and timeouts. These retry at the level of one network request, which is finer and cheaper than repeating a whole block in Jenkins. Use them first when they exist, and use the Jenkins retry step for the parts they do not cover.
Try and catch: retry’s clever cousin
When you need different behaviour by kind of error, such as retrying on a server error but stopping at a permission error, a small loop with try and catch gives you full control. It is more code, so keep it in a shared library step where every pipeline can reuse it.
Do not confuse retry with ignoring
The catchError step and its cousins do not retry. They accept a failure and continue. That is right for optional steps such as uploading a report, and wrong for steps the build cannot live without.
A toolbox has a screwdriver, a hammer, and a wrench. They all fasten things, but they are not interchangeable. Retry is the tool for “try that again,” timeout is for “stop if it takes too long,” and catchError is for “shrug and carry on.” Using the wrong one makes the job harder.
Ask three questions in order. Can the tool retry by itself? Can a small, well-placed retry step do it? Only then reach for custom loops.
13Retrying Whole Builds: Naginator and Rebuilds
Sometimes the trouble is spread across a whole build, and teams want the entire job to run again.
The Naginator plugin
The Naginator plugin adds a post-build action to Jenkins jobs, often labelled “Retry build after failure.” When a build fails, it schedules a new run of the same job. You can set the maximum number of reruns, choose whether waiting time between reruns is fixed or growing, and decide which failures qualify, for example only those whose log matches a chosen text. It was created for classic freestyle jobs, and it can also be used with some pipeline jobs.
Why whole-build retry is a blunt tool
- It repeats everything, including the stages that already passed.
- It hides the flakiness inside a single, long build rather than pointing at the flaky step.
- It multiplies cost: a one-hour build retried twice can consume three hours of agent time.
- Side effects such as deployments and published packages can be repeated.
When it still makes sense
Whole-build retry is defensible for older jobs that cannot easily be restructured, for nightly builds where extra time is cheap, or as a temporary bandage while a team fixes the real source of the flakiness. Set a small limit, a delay, and a matching rule so that only known transient failures trigger it.
Manual alternatives
Rebuild
A person starts the same build again, often with the same parameters. Useful for one-off reruns.
Restart from stage
In Declarative pipelines, a person can restart from a chosen stage, reusing earlier results. Best after a genuine fix.
Naginator
Automatic rerun of the whole job, with limits and rules.
Step-level retry
Automatic rerun of just the risky block. Usually the best choice for pipelines.
If one page of a printed report has a smudge, you reprint that page. Reprinting the whole two-hundred-page report because of one smudge wastes paper and time. Step-level retry reprints the page. Whole-build retry reprints the report.
Never combine whole-build retry with step-level retry without doing the arithmetic. Three build reruns each containing three step attempts can mean nine attempts of the same flaky action, and a very long, very expensive failure.
14Idempotency and Side Effects
The biggest danger of retry is not the wasted time. It is doing something twice that should have been done once.
What is idempotency?
An action is idempotent if doing it twice has the same effect as doing it once. Pressing the “floor five” button in an elevator ten times still takes you to floor five. Adding one to a counter ten times does not. Retry is only really safe around actions that behave like the first kind.
Actions that are usually safe to repeat
- Downloading a file or package.
- Reading data, or running a read-only check.
- Compiling code into a clean output folder.
- Uploading a file to a fixed name, replacing what was there.
- Setting a value to a specific state, such as “make sure this folder exists.”
Actions that are dangerous to repeat
- Sending emails or messages to customers.
- Charging money or creating orders.
- Appending lines to a shared file or log.
- Creating resources with generated names, so each attempt creates another one.
- Running a database change that is not written to be run twice.
- Incrementing version numbers, or tagging releases.
The half-done problem
A step can fail in the middle. The upload may have reached the server, but the confirmation was lost. From the pipeline’s point of view, the step failed. From the server’s point of view, the upload succeeded. A retry then uploads again. If the server rejects duplicates, the retry fails with a confusing “already exists” message. If it accepts duplicates, you now have two.
Making actions safe
Use fixed, predictable names
Name resources by build number or a stable key, so that a second attempt finds the first one instead of creating another.
Check before you act
Ask “does it already exist?” first, and skip the action when the answer is yes.
Use idempotency keys
Some services accept a unique key with each request and ignore repeats of the same key. Send the same key on each attempt.
Write repeatable changes
Design scripts and database changes so that running them twice leaves the same state.
Keep the retried block small
Wrap only the safe action, and leave the dangerous action outside.
If you drop a letter into a post box and are not sure it went in, posting a second copy might cause the recipient to receive two. If you had written a reference number on the letter, the recipient could ignore the duplicate. An idempotency key is that reference number.
Do not wrap a production deployment, a payment, or a customer message in a plain retry unless it has been designed to be repeated. A small wrapper can turn one problem into two.
15Cleaning Up Between Attempts
Retry does not sweep the floor. If the first attempt leaves a mess, the second attempt walks into it.
What a failed attempt can leave behind
Half-written files
A partial download that looks like a real file. The next attempt may treat it as complete and fail in a strange way.
Running processes
A server or test process that was started and never stopped, still holding a network port.
Containers and networks
Containers with fixed names that block a new container of the same name.
Lock files
A lock left by the failed tool, preventing the next run of the same tool.
Partial data
Rows or records written before the failure, in a test database.
Cloud resources
Half-created resources that later attempts try to create again.
Cleaning strategies
- Start each attempt clean. Put cleanup at the beginning of the retried block, so it runs before every attempt, including the first. Deleting a temporary folder and recreating it is a common pattern.
- Use unique working folders per attempt, if the workspace makes cleanup awkward.
- Use unique names for containers and resources, so a leftover cannot block a new one.
- Clean in a failure handler, using try and finally logic or the post section, so that resources are released even when the block fails.
- Prefer disposable environments. A fresh container per attempt is the cleanest cleanup of all.
Locks and retries
If your block holds a lock, such as one taken with the lockable resources feature, decide whether the lock should cover all attempts or each attempt separately. Holding the lock across all attempts keeps others out for longer. Releasing between attempts lets somebody else slip in and change the state you were preparing. Neither is universally right, but the choice should be deliberate.
| Leftover | Symptom on the next attempt | Fix |
|---|---|---|
| Partial download | Corrupt archive or checksum failure | Delete the file before each attempt |
| Old process on a port | Address already in use | Stop processes in a cleanup step |
| Container with same name | Name already in use | Use unique names, remove containers on failure |
| Leftover lock file | Another instance is running | Remove stale locks at the start |
| Half-created cloud resource | Already exists error | Check first, or use idempotent creation |
A painter who spills paint should clean the floor before the second try, not paint over the spill. Starting each attempt with a clean surface gives each attempt a fair chance.
16Flaky Tests: The Danger Zone
Wrapping a test stage in retry feels like an easy win. It is also the most misused application of the step.
What a flaky test is
A flaky test passes sometimes and fails sometimes on exactly the same code. Common causes include timing assumptions, shared test data, dependence on test order, outside services, and unpredictable resources like the clock or the network.
The temptation
Retrying the whole test stage makes red builds turn green, and the team’s pain goes away. But the flakiness is still there. It has just been hidden. Over time, the number of flaky tests grows, the retries grow, and build times grow with them. Worse, real bugs that fail intermittently get retried away, and they reach users.
The hidden cost
What retry gives
- Fewer red builds in the short term.
- Less clicking of rebuild.
- Time to fix the flaky tests properly.
What it takes away
- Visibility: flaky tests stop being noticed.
- Time: every retry adds minutes to the build.
- Honesty: a green build may hide a real intermittent bug.
- Discipline: the problem becomes permanent.
A better approach
Retry only the failing tests, not the stage
Some test frameworks and build tools can rerun just the tests that failed. This is precise and cheaper than repeating the whole suite.
Record every retry that helped
If a test passes only on retry, log it and report it as flaky, instead of quietly showing green.
Track a flaky list with owners
Every flaky test gets an owner and a deadline. A test that stays flaky for too long is quarantined or deleted.
Limit the retries
One retry is usually the most a test should get. If two retries are needed, the test is broken.
Fix the causes
Remove timing assumptions, isolate data, and stub the outside world. Retry is a bandage, not medicine.
A smoke alarm that beeps falsely gets its battery removed, and then the house is unprotected. Retrying flaky tests silences the false alarms, but it can also silence the real ones. The right fix is a better alarm, not a quieter one.
If a team’s build success rate depends on retries, measure how often the second attempt saves the build. If it is more than a few percent, the retry is masking a quality problem that deserves real attention.
17Security Considerations
Retrying looks harmless, but repeated actions can create security problems of their own.
Repeated wrong logins
Many systems lock an account after several failed logins. If a pipeline uses a wrong or expired password and retry runs the login three times, the account may be locked, and every other pipeline that uses it fails too. Never retry authentication failures. A rejected password will not become correct by waiting.
Rate limits and blocks
Servers that see many requests from one address may block it. A retry storm from a build farm can look like an attack. Respect rate-limit answers, wait as the server asks, and add backoff and jitter so your requests spread out.
Secrets in repeated logs
Every attempt writes to the build log. If a step prints details about the request, such as headers or command lines, three attempts print them three times. Make sure retried blocks do not print secrets, and that masking is active in each attempt.
Side effects with real consequences
A retried deployment step or message to a customer is not only a reliability problem. It can be a security and compliance problem too, for example a change that is applied twice and breaks an audit trail. Keep retried blocks away from sensitive actions unless they are designed for repetition.
Retry as a way to hide attacks
Intermittent failures can also be clues. A service that fails occasionally for a suspicious reason, such as intermittent certificate errors, may indicate a misconfiguration or an interception attempt. If retries always cover them up, nobody notices. Log retried failures and review them from time to time.
Safer habits
- Never retry login or permission failures.
- Use backoff, jitter, and small limits.
- Keep sensitive actions outside retried blocks.
- Log every retried failure for later review.
Risky habits
- Retrying authentication in a tight loop.
- Ignoring rate-limit answers.
- Printing secrets in retried steps.
- Silencing all intermittent errors.
A person who keeps entering a wrong PIN at a cash machine gets the card swallowed. Repeating a failed login is the same mistake at a larger scale. Some doors are locked for a reason, and knocking harder does not help.
18Performance, Cost, and Scalability
Every retry uses agent time, network capacity, and patience. At scale, small habits become big bills.
The cost of an attempt
If a block usually takes two minutes and fails three times before a lucky fourth attempt, it costs eight minutes of agent time, plus waiting. Multiply by hundreds of builds and dozens of stages, and retry can consume a noticeable share of your build capacity.
The retry budget
A retry budget is a limit on how much retrying is acceptable, for example “no more than five percent of attempts may be retries.” If retries exceed the budget, something is wrong in the underlying system, and the team must investigate rather than add more retries.
Practical guidance
Small counts
Two or three attempts are enough for most transient problems. If ten are needed, the service is broken.
Timeouts on every attempt
Cap the cost of one attempt and of the total.
Backoff with jitter
Prevents build farms from hammering a recovering service together.
Small blocks
Repeating a two-second download is cheap. Repeating a forty-minute test stage is not.
Use local mirrors and caches
Fewer outside calls means fewer chances to fail. A nearby package mirror removes many network failures altogether.
Fail fast on permanent errors
Use conditions so bugs do not consume retries.
Retries at scale
When the same outage hits hundreds of builds at once, retries multiply the load on the affected service. Build farms need a shared policy for backoff and jitter. A shared library step that every pipeline uses is the most practical way to enforce one policy across everything.
Root causes are cheaper than retries
Often the best performance improvement is to remove the cause of the transient failure: use a closer mirror, raise a connection limit, fix a slow database, or cache dependencies. Retry is the cheapest fix to write, and often the most expensive to keep.
Reheating a meal several times uses electricity every time. A well-run kitchen tries to serve it hot the first time. Retries are like reheating: sometimes necessary, but a habit that costs more than it seems.
19High Availability and Reliability
Retry helps a pipeline survive small hiccups. It cannot replace a reliable system underneath.
What retry can survive
- Short network problems: a dropped connection heals within seconds.
- Busy services: a server that briefly refuses work recovers.
- Lost build machines: another machine can take over the block.
- Controller restarts: some steps cannot resume afterwards, and a retry can run them again.
What retry cannot survive
- Long outages: if a service is down for an hour, three attempts over two minutes all fail.
- Permanent faults: wrong configuration, missing permissions, or code bugs.
- Corrupted state: a retry cannot repair a broken database or a damaged cache.
Agent loss and resumability
Pipelines are built to pause and resume, so many steps survive a restart of the Jenkins controller. But a running shell command on a machine that vanished cannot continue. That failure is an infrastructure failure, and the conditions of the retry step exist for exactly this. With cloud and container agents that come and go, agent loss becomes a normal event that a good pipeline expects.
Combine retry with other defences
Timeouts
Stop hung actions so retry can act.
Mirrors and caches
Reduce dependence on far-away services.
Alternative sources
If a primary registry fails repeatedly, try a backup one, which is a simple form of failover.
Circuit breaking
Stop retrying a service that has failed many times in a row, and report the outage instead.
Clear failure messages
When retries end, say exactly what failed and what people should check.
Fail loudly after the last attempt
A pipeline that swallows the final failure is worse than one that fails. Make sure that when all attempts are used, the build reports clearly, notifies the right people, and includes the reason from the last error.
Retries help the average build, but on-call engineers care about the bad day. Plan for the outage that lasts an hour, not only the blink that lasts a second.
A car’s spare tire helps with one flat. It does not help if the road is closed. Retry is the spare tire of a pipeline: excellent for the common puncture, useless when the whole bridge is out.
20Monitoring, Logging, and Metrics
A retry that nobody can see is a problem waiting to grow. Make retries visible.
Why visibility matters
Because retry turns failures into successes, a healthy-looking green dashboard can hide an unhealthy system. If half your builds need a second attempt, you are running on luck. Only measurement reveals it.
What to log
- The start of each retried block, with the limit.
- Each failure’s short reason, in plain words.
- The wait before the next attempt.
- The final result: succeeded on attempt two, or failed after three.
What to measure
Reading the numbers
| Pattern | What it probably means | Action |
|---|---|---|
| Rising retry rate for one step | A dependency is degrading | Investigate that service, add a mirror or cache |
| Retries almost never save the build | Failures are permanent, retry wastes time | Remove the retry or add conditions |
| Retries always save on attempt two | A steady, small flakiness | Fix the root cause while the retry holds |
| Spikes at particular hours | Shared resource contention or maintenance windows | Reschedule work, add capacity |
| Different failure texts | Several causes hidden under one retry | Split the block or add conditions |
Getting the data
Teams collect these measurements in several ways: by having a shared library step write a standard line to the log that a log system can count, by sending a small counter to a metrics system, or by reading build logs afterwards. A shared step that all pipelines use makes the data consistent.
Alerts
Alert the owning team when a step’s retry rate crosses an agreed threshold, when a retried block starts failing after all attempts, or when total retry time grows unusually. Do not alert on every single retry, because retries are working as designed.
Put a “builds saved by retry” number on a shared dashboard. Teams start asking why the number is so high, and that question leads to real fixes.
A car that needs two turns of the key every morning still gets you to work, but a good driver notices and visits the garage before winter. Retry counts are the number of times you turned the key.
21Testing Your Retry Logic
Retry code is rarely tested, because it seems simple. That is exactly why it hides bugs.
Why test it?
Retry runs only when things go wrong, so mistakes in it appear only on bad days. A wrong count, a missing wait, or a cleanup that fails can turn a small glitch into a long outage. Test retry on purpose, on a quiet day.
Ways to test
A step that fails first
Write a small test job with a step that fails the first one or two times and then succeeds, using a counter file in the workspace. Confirm that the block succeeds on the right attempt.
A step that always fails
Confirm that the failure escapes after the last attempt, with a clear message, and that the total time matches your budget.
A step that hangs
Confirm that the timeout cuts the attempt and that the retry then behaves as you expect in your Jenkins version.
Cleanup check
Leave debris on purpose in a failing attempt and confirm that the next attempt starts clean.
Permanent error
Confirm that a login failure or a compile error is not retried when conditions or filters say so.
Abort test
Press abort during a retry and confirm the build stops instead of starting another attempt.
Test shared library steps
If retry logic lives in a shared library step, it deserves unit tests with a pipeline testing framework, where you can simulate failures and check how many times the body ran and how long the waits were. Since this one step protects hundreds of pipelines, it deserves the best tests in your library.
Rehearse the outage
Once a quarter, deliberately break a dependency in a test environment, for example by blocking access to a mirror, and watch what happens to your pipelines. Do they retry sensibly? Do they fail with a clear message? Do the alerts fire?
A fire drill tests the exit doors on a calm day, so that people know what to do on a bad one. Failure drills for your pipelines serve the same purpose for your retry logic.
22Standard Retry Policy with Shared Libraries
When every team writes its own retry, you get dozens of styles. A shared library gives you one good one.
The problem with scattered retries
Without a common approach, one pipeline retries five times with no wait, another retries twice with a fixed wait, and a third has no retry at all. Some print helpful messages, and some print nothing. When an outage happens, some pipelines hammer the failing service, and others give up too early.
flowchart LR
T1["Team A Jenkinsfile"] --> LIB["Shared Library Retry Step"]
T2["Team B Jenkinsfile"] --> LIB
T3["Team C Jenkinsfile"] --> LIB
LIB --> POL["Standard Policy with limits, timeout, backoff and jitter"]
POL --> CLS["Failure Classifier for transient or permanent"]
CLS --> ACT["Retry with wait or fail fast"]
LIB --> LOG["Standard Log Lines and Metrics"]
LOG --> DASH["Dashboard and Alerts"]
What a standard retry step can do
- Apply a sensible default number of attempts and a per-attempt timeout.
- Add exponential backoff with jitter and a maximum delay.
- Classify failures as transient or permanent using known patterns, and fail fast on permanent ones.
- Print clear, uniform log lines for each attempt.
- Send a count to a metrics system.
- Refuse to wrap steps that are marked as unsafe to repeat.
Design guidelines
| Choice | Guideline |
|---|---|
| Default attempts | Three, including the first |
| Default wait | Short and growing, with jitter and a cap |
| Timeout | Required, with a sensible default |
| Overrides | Allowed within limits, so nobody can set a hundred attempts |
| Logging | Always on, never printing secrets |
| Name | Says what it does, such as a name that includes “withRetry” |
Cloud and configuration as code
Agents in the cloud come and go, and network calls cross many boundaries. Keep the retry defaults in the library and the library version in your configuration files, so a policy change reaches everyone through a reviewed release. Cloud teams often pair the pipeline policy with the retry settings built into their cloud tools, so that both layers cooperate rather than multiply.
Layered retries multiply. If your pipeline retries three times and the tool inside retries three times, one failing request is attempted nine times. Decide which layer owns the retry, and turn the other off.
A company that gives every branch its own way of handling a returned parcel gets confusion. One written procedure, followed by everyone, gives customers the same experience and gives managers one place to improve it. A shared retry step is that procedure.
23Advantages, Disadvantages, and Trade-offs
Retry is one of the cheapest ways to make pipelines calmer, and one of the easiest to misuse.
Advantages
- Short glitches heal without human help.
- Very small change to the pipeline.
- Reduces build noise and rebuild clicking.
- Works with any steps, in any pipeline style.
- Can be narrowed with conditions.
- Easy to standardise in a shared library.
Disadvantages
- Can hide flaky tests and real intermittent bugs.
- Repeats side effects if actions are not idempotent.
- Adds time and cost on failure.
- No built-in wait, so storms are easy to cause.
- Does not clean up leftovers.
- Layers of retry multiply attempts.
Resilience versus honesty
| Choice | Leans toward resilience | Leans toward honesty |
|---|---|---|
| Number of attempts | Several | One or two |
| Scope | Whole stage | Single action |
| Which failures | All of them | Only known transient ones |
| Reporting | Show green after a save | Mark the build as unstable when a retry was needed |
Showing that a retry happened
One useful compromise is to let the build succeed after a retry, but record that a retry was needed, for example in the build description or as a marker in the results. Then the pipeline stays green, and the team still sees the cost.
There is no universal answer. A team with a very stable internal network needs little retry. A team that downloads from the public internet through many hops needs more. Match the design to your environment, your risks, and your patience.
24Design Patterns and Anti-patterns
A pattern is a solution many teams discovered independently. An anti-pattern is a trap many teams fell into.
Patterns worth copying
Small block, per-attempt timeout
Wrap one flaky action, with a timeout inside the retry, and a small attempt limit.
Backoff with jitter
Wait a growing, slightly random time between attempts, up to a cap.
Clean start
Begin each attempt by clearing leftovers, so each one starts fresh.
Fail fast on permanent errors
Use conditions or classification so bugs and bad credentials stop immediately.
Backup source
After repeated failure on a primary mirror, try a secondary one.
Mark saved builds
Record that a retry was needed, so hidden flakiness stays visible.
Anti-patterns to avoid
The Blanket Retry
Putting retry around the entire pipeline or around every stage “just in case.” Bugs are repeated, time is wasted, and real problems are hidden.
Better approach
Retry only specific, known-flaky actions, with conditions or classification.
The Instant Hammer
Retrying immediately, many times, with no wait. It adds load to a service that is already struggling.
Better approach
Add a wait, growing with each attempt, with jitter and a cap.
Retry Wrapped Around Deploy
Wrapping a deployment or payment in retry when it is not safe to repeat. Two deployments or two charges result.
Better approach
Make the action idempotent first, or keep it outside the retry block.
The Retry Tower
Retries inside retries inside retries: the pipeline, the stage, the step, and the tool each retry three times. One failure turns into eighty-one attempts.
Better approach
Choose one layer to own the retry and disable the others.
The Silent Save
Retrying without logging or metrics, so nobody knows how often builds are being rescued.
Better approach
Log every attempt and count retries. Review the numbers regularly.
25Best Practices and Common Mistakes
These are lessons that teams usually learn the hard way. You can learn them the easy way.
Best practices
- Retry only transient failures. Fail fast on bugs, bad configuration, and login errors.
- Keep the retried block small, wrapping one action rather than a whole stage.
- Use a timeout inside every retry that touches a network or a slow tool.
- Add a wait, ideally growing, with jitter and a cap.
- Keep attempts low, normally two or three.
- Make retried actions idempotent and start each attempt from a clean state.
- Prefer the tool’s own retry for single requests, and own only one retry layer.
- Log each attempt and never print secrets.
- Measure retry rate and save rate, and set a budget.
- Standardise in a shared library so all teams follow one policy.
- Fix root causes, using retry as a bridge, not a home.
Common mistakes and their fixes
| Mistake | What happens | Fix |
|---|---|---|
| Assuming the limit means extra retries | One attempt fewer than expected | Remember that the count includes the first attempt |
| No timeout inside the retry | A hung attempt blocks everything | Add a per-attempt timeout |
| Retrying login failures | Accounts get locked | Do not retry authentication and permission errors |
| Retrying the whole test stage | Flaky tests hide, builds slow down | Rerun only failing tests and track flakiness |
| No cleanup between attempts | Second attempt fails for a different reason | Clean at the start of the block |
| Layered retries | Attempts multiply | Choose one owning layer |
| Retry around a non-idempotent action | Duplicate deployments, messages, or charges | Redesign, or keep it outside the block |
| Not reading the first failure | Debugging the second, misleading error | Read all attempts, starting with the first |
The build is green, so nobody looks. But the log shows three attempts on every download. The pipeline is healthy in appearance only. Review retried steps regularly, even when the builds are green.
26A Worked Example: Hardening a Flaky Pipeline
Let us walk through a full improvement for a fictional team, step by step, without writing any code.
The situation
Harbourline Software has a web service pipeline with five stages: fetch dependencies, compile, unit tests, build a container image, and publish the image to a registry. About one build in six fails for no clear reason. Developers press rebuild without reading the log, and the on-call engineer has stopped trusting red builds.
Step by step
Collect evidence
The team reads the logs of thirty failed builds and sorts the failures: twelve were dependency downloads, six were the registry publish, five were lost build machines, and seven were real test failures.
Decide what is transient
Downloads, publishing, and lost machines are transient. Real test failures are not. The team resolves not to retry tests.
Fix causes first where cheap
They set up a local package mirror, which removes most download failures without any retry.
Wrap the download
The remaining download step gets a small retry of three attempts, with a per-attempt timeout of five minutes and a short growing wait with jitter.
Make publishing safe to repeat
The publish step is changed to use the build number as a fixed tag. Before publishing, it checks whether the tag already exists. Only then is the publish step wrapped in a retry of two attempts.
Handle lost machines with conditions
For the compile and build stages, the team uses a retry with agent-loss conditions, so infrastructure failures are retried and code errors are not.
Add cleanup
Each retried block begins by removing partial downloads and temporary containers with fixed names.
Log and measure
A shared library step prints each attempt and records a count. The build description notes when a retry was needed.
Review after a month
The team compares retry rate, save rate, and build duration, and decides what else to fix.
The result after one month
| Measure | Before | After |
|---|---|---|
| Builds failing for unclear reasons | About one in six | About one in fifty |
| Manual rebuilds per week | Dozens | A handful |
| Real test failures noticed quickly | Often ignored | Taken seriously again |
| Retries that saved a build | Not measured | Tracked, and falling as causes are fixed |
The team did not start by adding retry everywhere. It started by reading the failures, fixed the cheapest causes, and used retry only where the evidence showed transient trouble. Evidence first, retry second.
27Migrating from Blanket Retries to a Retry Policy
Many teams already have retries scattered around. Here is how to bring order without breaking builds.
What you may find
- A retry around the whole pipeline, added years ago by someone who has left.
- A stage option that retries a slow test stage five times.
- A hand-written loop with an unknown number of attempts and no wait.
- A whole-build retry plugin setting on old jobs.
- Tool-level retries inside scripts, combining with pipeline retries.
A safe migration path
Inventory
Search all Jenkinsfiles, shared libraries, and job settings for retries, loops, and rerun plugins. Write down where each one is and what it wraps.
Measure before touching
For a few weeks, record how often each retry actually saves a build. Retries that never save anything are candidates for removal.
Remove the dangerous ones first
Take retries away from deployment, publishing, and payment steps, unless they are made idempotent.
Narrow the broad ones
Replace stage-wide and pipeline-wide retries with retries around the specific flaky actions.
Introduce the standard step
Publish the shared library retry step, and convert pipelines to use it a few at a time.
Fix root causes
Where measurements show a steady flaky action, invest in a real fix such as a mirror, a cache, or a corrected test.
Retire whole-build retry
Once step-level retry is in place, turn off rerun plugin settings so attempts do not multiply.
Removing a long-standing retry can make builds seem to get worse overnight, because the hidden flakiness suddenly shows. Warn the team, and treat the newly visible failures as valuable information, not as a regression.
The reward
After migration, every retry in your pipelines is deliberate, small, measured, and safe. Failures that remain are meaningful, and the team trusts red builds again.
28Team Agreements: Living with Retries
A retry policy works best when the team agrees on it and reviews it together.
Agree on the defaults
Write down the standard number of attempts, the standard wait, the standard timeout, and where these are set. Put them in the contributing guide, so that every new pipeline follows the same rules.
Agree on what may be retried
- A list of actions that are approved for retry: downloads, uploads to fixed names, readiness checks.
- A list of actions that must never be retried without redesign: payments, customer messages, uncontrolled deployments.
- A rule that authentication and permission failures are never retried.
Agree on visibility
Every retry writes a standard log line and counts toward a shared metric. A weekly or monthly review looks at the top retried steps and asks what could remove the need.
Agree on ownership
The owner of the shared retry step decides defaults, reviews requests for exceptions, and publishes changes. Each team owns the retries in its own pipelines and answers for their numbers.
Retry needs a reason
Every retry in a pull request comes with a short note about which failure it targets.
Retry has an owner
Someone is responsible for revisiting it and removing it when the cause is fixed.
Retry is measured
Numbers, not feelings, decide whether a retry stays.
Retry is temporary where possible
A retry that hides a fixable problem should carry a target date for removal.
A hospital has a written rule for when a test may be repeated and when a doctor must be called. Without the rule, one nurse repeats everything and another repeats nothing. A team retry policy is the same kind of shared rule.
29Real-World and Industry Examples
These scenarios show how organisations use retry. They are illustrative, so you can map them to your own situation.
Scenario: the public package registry that blinks
A team downloads hundreds of libraries from a public registry for every build. Once or twice a day the registry answers with a temporary error for a few seconds. A small retry with a short wait around the dependency step turns those blips into invisible events. Later the team adds a local mirror, and the retry rarely fires.
Scenario: cloud agents that disappear
A company runs Jenkins agents as short-lived containers on a shared cluster. Occasionally the cluster reclaims a container in the middle of a build. A retry with an agent-loss condition restarts the block on a fresh container. Builds succeed, and the team sees the occasional retry in a dashboard without any human action.
Scenario: the readiness check after deployment
After deploying a service to a test environment, a pipeline must wait until it is ready. Instead of retrying a failing check, the team uses a wait-until step with growing pauses and a firm time limit. If the service is not ready after ten minutes, the pipeline fails with a clear message.
Scenario: the rate-limited service
Many builds call a public service that limits requests. When the limit is hit, it says so and asks clients to wait. The shared retry step respects that answer, waits a random amount around the requested time, and tries again, so the build farm does not hammer the service as a crowd.
Scenario: the retry that hid a real bug
A team wrapped its test stage in retry three years ago. Slowly the stage grew from ten to thirty minutes. Investigation showed that a genuine race condition in the product caused one test to fail about a third of the time, and the retry had been hiding it. Removing the retry made the bug visible, and fixing it improved both the product and the build time.
What these examples share
In every good case, retry targets a known transient cause, sits around a small, safe block, has a timeout and a wait, and is measured. In the bad case, retry was broad, silent, and unmeasured, and it hid the very information the team needed.
30How Other CI Tools Handle Retries
Every modern automation system offers some way to deal with transient failure. Comparing them shows what is essential.
| Tool | Its approach to retry | Notable difference |
|---|---|---|
| Jenkins | The retry step, stage and pipeline options, plus plugins for whole-build reruns | Flexible and code-based; you build the wait and classification yourself |
| GitLab CI/CD | A retry setting on jobs, with a maximum and optional conditions such as runner failures | Configured per job, with built-in failure categories |
| Azure Pipelines | A retry count on tasks | Simple per-task count |
| Buildkite | Automatic retry rules by exit status | Rules keyed by exit codes |
| GitHub Actions | No general built-in step retry as far as I know; teams use community actions, shell loops, or rerun failed jobs manually | Manual rerun of failed jobs is a first-class feature |
| CircleCI | Reruns of failed jobs or tests, with test-level rerun options | Focus on rerunning failed tests |
Feature sets change quickly, so check each tool’s current documentation before you rely on this table.
What Jenkins does differently
Jenkins gives you a small, general building block and expects you to compose a policy from it: timeouts, waits, conditions, and shared library steps. Some other tools bake failure categories into job settings. Jenkins gives more freedom and more responsibility, which is why a shared standard step is so valuable.
What is universal
The lessons apply everywhere: retry transient failures only, keep blocks small and safe to repeat, wait with backoff and jitter, cap attempts and time, own one retry layer, and measure how often retries save the build.
31Advanced Topics: Circuit Breakers, Budgets, and Classification
Once the basics feel comfortable, these ideas help larger teams and busier build farms.
Circuit breakers
A circuit breaker is a rule that stops trying a service that keeps failing. In an electrical panel, a breaker trips when there is too much current, protecting the wiring. In a pipeline, a breaker might say, “if the registry failed the last ten builds in a row, stop retrying and fail immediately with a clear outage message.” This saves time and reduces the load on the struggling service.
Failure classification
A custom retry step can look at the failure and decide what kind it is: a network error, a rate limit, a timeout, an authentication error, or a build failure. Each class gets its own treatment. Network errors get a retry with backoff. Rate limits get a longer, server-guided wait. Authentication errors and build failures fail at once. Keep the list of patterns small, tested, and documented.
Exit codes
Command-line tools report their result as a number called an exit code. Zero means success. Other numbers mean various kinds of failure, and some tools use specific codes for temporary problems. A custom step can capture the exit code and retry only for codes known to be transient.
Retry budgets across the pipeline
Instead of allowing three attempts per step, a pipeline might have a total budget, such as “at most five retries across the entire run.” When the budget is used up, the next failure fails immediately. This stops a sick run from consuming an hour of retries across many stages.
Idempotency keys
For actions that call outside services, send a unique key with each logical request, the same on every attempt. The service can recognise duplicates and process the request only once. Where a service supports keys, this makes retry safe even for actions like creating orders or launching cloud resources.
Hedging and other tricks
Some large systems send a second request if the first is slow, without waiting for failure, and use whichever answers first. This trades extra load for lower delay. It is rarely appropriate for build pipelines, but it shows the wider family of techniques that retry belongs to.
Circuit breaker
Stop trying a service that keeps failing.
Classifier
Choose the treatment by kind of failure.
Run-wide budget
Cap total retries across the pipeline.
Idempotency keys
Let outside services ignore duplicate requests.
Add advanced features one at a time, and only after the simple version is measured and stable. A clever retry policy that nobody understands is another source of surprise.
32Troubleshooting Retry Behaviour
When something feels wrong, walk through these questions in order.
How many attempts really ran?
Count the attempts in the log. Remember that the limit includes the first attempt, so a limit of three shows three runs, not four.
What did the first attempt fail with?
Read the first failure, not the last. Later failures are often side effects of a messy first one.
Why was no retry performed?
Check for a human abort, for retry conditions that did not match, and for a failure raised outside the retried block.
Why did it retry so many times?
Look for layered retries: a pipeline option, a stage option, a step, a plugin, and a tool option may all be active together.
Did the attempt hang?
A hung attempt never fails, so retry never acts. Check for a timeout inside the retry, and how your version treats a timeout.
What did the previous attempt leave behind?
Look for partial files, running processes, existing containers, and stale locks.
Did a side effect repeat?
Check the target system for duplicates: two deployments, two messages, two resources. If found, remove the retry or make the action idempotent.
| Symptom | Likely cause | First check |
|---|---|---|
| Build takes far longer than usual | Repeated attempts, each with long timeouts | Count attempts and durations in the log |
| Second attempt fails with a different error | Leftovers from the first attempt | Cleanup at the block start |
| No retry happens at all | Condition did not match, or human abort | Conditions and how the failure was raised |
| Duplicate resources or messages | Non-idempotent action inside retry | What the block does on repeat |
| Account locked out | Login failure was retried | Remove retry from authentication |
| Service overwhelmed after an outage | Retry storm without jitter | Add backoff and jitter in a shared step |
Keep a short page for developers explaining how retries are set up in your pipelines, what the standard defaults are, and how to read a log with several attempts. It prevents many panicked messages.
33Glossary of Terms
Every important word from this guide in one place, explained in plain language.
| Term | Plain meaning |
|---|---|
| Agent | A worker machine or container that runs pipeline steps for Jenkins. |
| Attempt | One run of the steps inside a retry block. The first run counts as attempt one. |
| Backoff | Waiting between attempts, usually longer each time. |
| Build noise | Failures that have nothing to do with code quality, which erode trust in builds. |
| Circuit breaker | A rule that stops trying a service that keeps failing. |
| Condition | A test that decides whether a failure deserves a retry. |
| Controller | The central Jenkins server that runs pipelines and schedules work. |
| Exception | The signal a failing step raises to say that something went wrong. |
| Exit code | The number a command returns to report its result, with zero meaning success. |
| Flaky test | A test that sometimes passes and sometimes fails on the same code. |
| Idempotent | Safe to repeat, because a second run leaves the same result as the first. |
| Idempotency key | A unique key sent with a request so that a service can ignore repeats. |
| Jenkinsfile | The text file that defines a pipeline, stored beside the source code. |
| Jitter | A small random change to waiting time so clients do not retry in unison. |
| Naginator | A plugin that reruns a whole build after failure. |
| Permanent failure | A problem that stays until someone fixes it. |
| Rate limit | A server’s cap on how many requests a client may make in a period. |
| Retry budget | A limit on how much retrying is acceptable overall. |
| Retry storm | Many clients retrying together and overwhelming a recovering service. |
| Stage | A named phase of a pipeline, such as Build or Test. |
| Step | One action inside a pipeline. |
| Timeout | A maximum time allowed for a block of steps. |
| Transient failure | A problem that goes away by itself, such as a brief network error. |
| waitUntil | A Jenkins step that repeats a check until it returns true. |
34Frequently Asked Questions
Short answers to the questions people ask most.
35Summary and Key Takeaways
The retry step gives a pipeline a second chance. Used with judgement, it makes builds calmer. Used carelessly, it hides the very problems you need to see.
You began with a coffee machine that needed a second press and finished with a full policy for retrying pipeline steps. Along the way you learned how the count works, how the block restarts, how to add timeouts and waiting, how to tell transient failures from permanent ones, why idempotency and cleanup matter, and how to measure and standardise retries across a team. The main rules are simple: retry only transient failures, keep the block small, add a timeout and a wait, make the action safe to repeat, and measure what you rescue.
Key Takeaways
- Retry repeats a block after failure. The count includes the first attempt, the whole block restarts, and only the final failure escapes.
- Retry transient failures only. Network blips, busy servers, and lost agents deserve another try. Bugs, bad configuration, and wrong passwords do not.
- Always pair retry with a timeout, and add a wait. A hung attempt never fails, and instant retries can start a storm. Use backoff with jitter and a cap.
- Make retried actions safe to repeat. Use idempotent actions, fixed names, existence checks, and idempotency keys, and clean up leftovers at the start of each attempt.
- Keep the scope small and the layers few. Wrap one action, not a stage or a pipeline, and let only one layer own the retry so counts do not multiply.
- Do not use retry to hide flaky tests. Rerun only failing tests, record every save, and fix the causes.
- Standardise and measure. Use a shared library step with one policy, log each attempt, track retry and save rates, and set a budget.