Skip to content

fix(docker): disambiguate self-inflicted ping timeout from daemon refusal - #1097

Merged
skevetter merged 2 commits into
mainfrom
fix/podman-ping-timeout-disambiguation
Aug 17, 2026
Merged

fix(docker): disambiguate self-inflicted ping timeout from daemon refusal#1097
skevetter merged 2 commits into
mainfrom
fix/podman-ping-timeout-disambiguation

Conversation

@skevetter

@skevetter skevetter commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Root cause

up-provider-podman-rootless-exec (and its rootful/rootless siblings) intermittently fail with:

{"kind":"error","outcome":"error","message":"start workspace: signal: killed: podman daemon is not reachable"}

CI run: https://github.com/devsy-org/devsy/actions/runs/32065209141

This is not a genuinely unreachable daemon:

  • signal: killed is Go's default error when exec.Cmd.Cancel kills a process on context cancellation -- never something podman itself emits.
  • Ping (pkg/docker/helper.go) builds its podman info command with a hard-coded context.WithTimeout(ctx, 10*time.Second), and the failing run's surrounding log span reports elapsed=10.156166312s -- almost exactly that deadline.
  • podman info was therefore still running, not refused, when Devsy killed it and declared the daemon down.
  • Ping predates runCmd (added in fix: disambiguate signal-killed errors from context cancellation #896 specifically to disambiguate a self-inflicted context-cancel kill from a genuine command failure) and was never migrated onto it, so runPreflight had no way to tell "we gave up early" apart from "the daemon said no".

Confirmed by reproducing the exact pre-fix code path in isolation: a raw buildCmd(...).CombinedOutput() on a killed process returns bare err = "signal: killed" with no context.DeadlineExceeded attached -- reproducing the CI failure message verbatim.

Existing CI mitigations (--ginkgo.flake-attempts=2, dpkg-lock wait, job/test timeout bumps from #1049) target installation-time races and whole-spec timeouts; none touch this in-process 10s ping deadline, so retrying just re-rolls the same race under sustained CI resource contention.

Fix

  • Ping, StartPodmanMachine, and the systemctl --user start podman.socket call in StartRootlessPodmanSocket now route through runCmd (via a new runCmdCombined helper), so a self-inflicted timeout kill is wrapped with ctx.Err() and errors.Is(err, context.DeadlineExceeded) works.
  • pingTimeout raised from a hard-coded 10s to 30s (still well under the 90s Podman-machine-boot budget).
  • runPreflight now reports "daemon did not respond in time (it may just be slow to start, not necessarily down)" when the ping error carries context.DeadlineExceeded, instead of unconditionally claiming the daemon "is not reachable".

Testing

  • New regression tests in pkg/docker/helper_test.go and pkg/driver/docker/preflight_test.go force the internal deadlines via overridable package vars and assert errors.Is(err, context.DeadlineExceeded), plus assert a fast native refusal is not misattributed to a timeout.
  • All existing TestRunPreflight* table tests pass unchanged.
  • go build, gofmt -l, and go test ./pkg/docker/... ./pkg/driver/docker/... all pass.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Docker and Podman startup and connectivity handling.
    • Extended Docker ping detection to allow more time for slow-starting daemons.
    • Error messages now distinguish between unreachable daemons and daemons that do not respond in time.
    • Preserved timeout details to provide clearer diagnostics when startup commands exceed their limits.

…usal

Ping killed a still-running `podman info` at its own hard-coded 10s
deadline under CI runner CPU/IO contention (CI run 32065209141,
up-provider-podman-rootless-exec), then reported the bare "signal:
killed" from that kill as an unqualified "daemon is not reachable" --
indistinguishable from a genuine refusal. This masqueraded as test
flakiness; --ginkgo.flake-attempts=2 just re-rolled the same race.

Ping, StartPodmanMachine, and the systemctl call in
StartRootlessPodmanSocket now route through runCmd (via a new
runCmdCombined helper) so a kill caused by our own context deadline is
wrapped with ctx.Err(), and pingTimeout is raised from 10s to 30s.
runPreflight reports a distinct 'did not respond in time' message when
the ping error carries context.DeadlineExceeded, instead of always
asserting the daemon is down.
@netlify

netlify Bot commented Aug 17, 2026

Copy link
Copy Markdown

Deploy Preview for devsydev canceled.

Name Link
🔨 Latest commit f937458
🔍 Latest deploy log https://app.netlify.com/projects/devsydev/deploys/6a837c471317040008e61029

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e03c4f68-3334-4faa-b4fb-de212ded77be

📥 Commits

Reviewing files that changed from the base of the PR and between 31f2112 and cb1bd09.

📒 Files selected for processing (4)
  • pkg/docker/helper.go
  • pkg/docker/helper_test.go
  • pkg/driver/docker/docker.go
  • pkg/driver/docker/preflight_test.go

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds shared command output handling, increases the ping timeout to 30 seconds, makes Podman startup timeouts configurable, and distinguishes Docker daemon timeout errors from other preflight failures.

Changes

Timeout error handling

Layer / File(s) Summary
Shared command execution and timeout coverage
pkg/docker/helper.go, pkg/docker/helper_test.go
runCmdCombined now captures command output and includes it in execution errors. Ping, Podman machine startup, and rootless Podman socket startup use the helper. Tests cover successful commands, refusal errors, and command timeouts.
Docker preflight error classification
pkg/driver/docker/docker.go, pkg/driver/docker/preflight_test.go
Docker preflight now reports deadline failures as non-responsive daemon errors and preserves the generic unreachable-daemon message for other failures. Tests verify both classifications.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to cb1bd

This localized change distinguishes slow daemon startup from genuine refusal and extends the ping timeout, with regression coverage and passing checks; no actionable merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: distinguishing self-inflicted ping timeouts from daemon refusal errors.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/podman-ping-timeout-disambiguation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@netlify

netlify Bot commented Aug 17, 2026

Copy link
Copy Markdown

Deploy Preview for images-devsy-sh canceled.

Name Link
🔨 Latest commit f937458
🔍 Latest deploy log https://app.netlify.com/projects/images-devsy-sh/deploys/6a837c474f658b0008f8e27d

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 5 complexity · -5 duplication

Metric Results
Complexity 5
Duplication -5

View in Codacy

AI Reviewer: run a review on demand. To trigger the first review automatically, go to your organization or repository integration settings. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@skevetter
skevetter marked this pull request as ready for review August 17, 2026 21:21
@skevetter
skevetter enabled auto-merge (squash) August 17, 2026 21:25
@skevetter
skevetter disabled auto-merge August 17, 2026 21:51
@skevetter

Copy link
Copy Markdown
Contributor Author

@Mergifyio queue

@mergify

mergify Bot commented Aug 17, 2026

Copy link
Copy Markdown

Merge Queue Status

  • 🟠 Waiting for queue conditions
  • ⏳ Enter queue
  • ⏳ Run checks
  • ⏳ Merge
Waiting for
  • -closed [📌 queue requirement]
  • any of: [🛡 GitHub repository ruleset rule default]
    • check-neutral = @github-actions/Check Commits
    • check-skipped = @github-actions/Check Commits
    • check-success = @github-actions/Check Commits
  • any of: [🛡 GitHub repository ruleset rule default]
    • check-neutral = @github-actions/Check Contributor License Agreement
    • check-skipped = @github-actions/Check Contributor License Agreement
    • check-success = @github-actions/Check Contributor License Agreement
  • any of: [🛡 GitHub repository ruleset rule default]
    • check-neutral = @github-actions/lint-and-test
    • check-skipped = @github-actions/lint-and-test
    • check-success = @github-actions/lint-and-test
All conditions
  • -closed [📌 queue requirement]
  • any of [🔀 queue conditions]:
    • all of [📌 queue conditions of queue rule default]:
      • any of [🛡 GitHub repository ruleset rule default]:
        • check-neutral = @github-actions/Check Commits
        • check-skipped = @github-actions/Check Commits
        • check-success = @github-actions/Check Commits
      • any of [🛡 GitHub repository ruleset rule default]:
        • check-neutral = @github-actions/Check Contributor License Agreement
        • check-skipped = @github-actions/Check Contributor License Agreement
        • check-success = @github-actions/Check Contributor License Agreement
      • any of [🛡 GitHub repository ruleset rule default]:
        • check-neutral = @github-actions/lint-and-test
        • check-skipped = @github-actions/lint-and-test
        • check-success = @github-actions/lint-and-test
      • github-review-approved [🛡 GitHub repository ruleset rule default]
      • any of [🛡 GitHub repository ruleset rule default]:
        • check-success = @github-actions/Lint
        • check-neutral = @github-actions/Lint
        • check-skipped = @github-actions/Lint
      • any of [🛡 GitHub repository ruleset rule default]:
        • check-success = @github-actions/Pre-commit
        • check-neutral = @github-actions/Pre-commit
        • check-skipped = @github-actions/Pre-commit
      • any of [🛡 GitHub repository ruleset rule default]:
        • check-success = @github-actions/CI Success
        • check-neutral = @github-actions/CI Success
        • check-skipped = @github-actions/CI Success
  • -conflict [📌 queue requirement]
  • -draft [📌 queue requirement]
  • any of [📌 queue -> configuration change requirements]:
    • -mergify-configuration-changed
    • check-success = Configuration changed

@skevetter
skevetter enabled auto-merge (squash) August 17, 2026 21:53
@skevetter
skevetter merged commit b357a95 into main Aug 17, 2026
136 of 138 checks passed
@skevetter
skevetter deleted the fix/podman-ping-timeout-disambiguation branch August 17, 2026 22:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant