Skip to content

Harden Linux Docker retries in CI#8358

Merged
NachoEchevarria merged 54 commits into
masterfrom
dd/ci/linux-docker-cgroup-retries
Apr 9, 2026
Merged

Harden Linux Docker retries in CI#8358
NachoEchevarria merged 54 commits into
masterfrom
dd/ci/linux-docker-cgroup-retries

Conversation

@NachoEchevarria

@NachoEchevarria NachoEchevarria commented Mar 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add Linux Docker readiness check to CI, mirroring the existing Windows approach (PR #8245). Targets transient cgroup/systemd/dbus failures — the largest CI flake category (10 commits blocked).

Reason for change

retryCountOnTaskFailure retries on the same agent, so if Docker is broken on that VM, all retries fail. This adds active recovery (service restart) before Docker commands run.

For instance:

2026-03-25T15:05:08.0833114Z docker: Error response from daemon: failed to create task for container: Unavailable: error reading from server: EOF
2026-03-25T15:05:08.0833917Z 
2026-03-25T15:05:08.0834644Z Run 'docker run --help' for more information

Changes

  • New ensure-docker-ready-linux.sh: waits for Docker daemon, attempts systemctl restart docker if the service is down (mirrors Windows Restart-Service), emits diagnostics on failure
  • ensure-docker-ready.yml: Linux readiness step added alongside existing Windows step
  • run-in-docker.yml: embedded ensure-docker-ready.yml call — automatically covers all ~27 Linux jobs that use this template.
  • ultimate-pipeline.yml: added readiness check to integration_tests_windows_msi job (the only uncovered Windows docker-compose caller)

@NachoEchevarria
NachoEchevarria marked this pull request as ready for review March 27, 2026 09:30
@NachoEchevarria
NachoEchevarria requested a review from a team as a code owner March 27, 2026 09:30
#!/usr/bin/env bash
# Linux Docker readiness check — mirrors the Windows PowerShell logic in ensure-docker-ready.yml.
# Waits for the Docker daemon, attempts service restarts if needed, and fails fast
# so the job can be rescheduled on a different agent.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# so the job can be rescheduled on a different agent.

This doesn't happen automatically though right, you have to manually retry? But it would never work anyway, so that's fine, just checking 🙂

# Waits for the Docker daemon, attempts service restarts if needed, and fails fast
# so the job can be rescheduled on a different agent.

set -u

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably exit on failing commands too? Or does that break things? Meh, maybe best to leave it 😅

Suggested change
set -u
set -eu

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should avoid early exits in some commands that could possibly fail in the script

fi

# If Docker is not responding, try restarting the service
if command -v systemctl >/dev/null 2>&1; then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this command fails (because systemctl is not available, then we don't actually restart anything, so we may as well just exit early instead I think? We can do that after logging the docker state if we want to. Alternatively, we could just not restart it, but still try to wait?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment on lines +96 to +97
log "Docker service is ${svc_status}. Attempting restart ${restart_count}/${DOCKER_MAX_RESTARTS}..."
try_restart_docker

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(suggestion based on previous comment)

Suggested change
log "Docker service is ${svc_status}. Attempting restart ${restart_count}/${DOCKER_MAX_RESTARTS}..."
try_restart_docker
if ! command -v systemctl >/dev/null 2>&1; then
log "Docker service is ${svc_status}, but systmctl is not available, so unable to explicitly restart service."
else
log "Docker service is ${svc_status}. Attempting restart ${restart_count}/${DOCKER_MAX_RESTARTS}..."
try_restart_docker
fi

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, we are already checking systemctl is-active docker in line 93, so if we reach this part of the code, the command was successful. I will leave the original code. WDYT?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, buy the problem is if it wasn't successful, we end up stuck in this loop where we're just sleeping repeatedly, not restarting anything, but still sleeping 🤔 That's the scenario this is trying to highlight 😄

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added!

@@ -0,0 +1,113 @@
#!/usr/bin/env bash

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally we try to just use POSIX shell instead of bash - if it's simple to convert to that, then it may save us some pain later

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! Done!

Comment thread .azure-pipelines/steps/ensure-docker-ready.yml Outdated
Comment thread .azure-pipelines/steps/run-in-docker.yml Outdated
displayName: BuildWindowsIntegrationTests
retryCountOnTaskFailure: 3

- template: steps/ensure-docker-ready.yml

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch 👍

@NachoEchevarria
NachoEchevarria requested a review from a team as a code owner March 27, 2026 12:13

@andrewlock andrewlock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@NachoEchevarria
NachoEchevarria merged commit 549e87e into master Apr 9, 2026
137 checks passed
@NachoEchevarria
NachoEchevarria deleted the dd/ci/linux-docker-cgroup-retries branch April 9, 2026 14:20
@NachoEchevarria

Copy link
Copy Markdown
Collaborator Author

Thank you for the feedback and review!

@github-actions github-actions Bot added this to the vNext-v3 milestone Apr 9, 2026
NachoEchevarria added a commit that referenced this pull request Apr 21, 2026
## Summary of changes

Add a targeted retry wrapper around `docker run` in `run-in-docker.yml`
to handle transient Docker daemon errors without blanket-retrying the
entire CI step.

## Reason for change

After merging #8358 (Docker daemon readiness checks), we still observed
transient failures where the daemon was confirmed ready but `docker run`
failed with D-Bus/cgroup errors like:

> `unable to start unit "docker-....scope": Message recipient
disconnected from message bus without replying`

The daemon is healthy (passes `docker info`), but systemd's D-Bus has a
momentary hiccup during container cgroup creation. This is a transient
infrastructure issue, not a test failure.

## Implementation details

- Adds a `docker_run_with_retry` shell function that wraps the `docker
run` invocation
- **Only retries on exit code 125** (Docker daemon error — container
creation failure), up to 3 attempts with 10s delay
- **Does not retry** on any other exit code (test/build failures inside
the container pass through immediately)
- **Always logs the exit code** on failure (`##[warning]`), so we can
observe actual exit codes for future Docker errors regardless of whether
they trigger a retry

## Test coverage

CI pipeline change — no unit tests. Validated by reviewing Docker's exit
code conventions (125 = daemon error).

## Other details

Follow-up to #8358.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos area:builds project files, build scripts, pipelines, versioning, releases, packages type:flake-fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants