-
Notifications
You must be signed in to change notification settings - Fork 0
Retry transient fresh LXC starts #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -78,13 +78,28 @@ cpu_count() { | |
| printf '%s' "$total" | ||
| } | ||
| start() { | ||
| [[ "$(state "$1")" == "RUNNING" ]] || lxc-start -P "$LXC_PATH" -n "$1" -d | ||
| local attempt | ||
| for attempt in {1..200}; do | ||
| [[ "$(state "$1")" == "RUNNING" ]] && return | ||
| sleep 0.1 | ||
| local name="$1" start_attempt state_attempt detail="" | ||
| [[ "$(state "$name")" == "RUNNING" ]] && return | ||
| # A freshly unpacked container can hit LXC's daemonized-start socket race: | ||
| # lxc-start exits after wait_on_daemonized_start loses the state message even | ||
| # though the container definition is intact and immediately startable. Check | ||
| # the authoritative state after every invocation and retry that same exact | ||
| # validated machine instead of failing channel creation on the transient. | ||
| for start_attempt in {1..3}; do | ||
| if ! detail="$(lxc-start -P "$LXC_PATH" -n "$name" -d 2>&1)"; then | ||
| for state_attempt in {1..50}; do | ||
| [[ "$(state "$name")" == "RUNNING" ]] && return | ||
| sleep 0.1 | ||
| done | ||
| continue | ||
| fi | ||
| for state_attempt in {1..200}; do | ||
| [[ "$(state "$name")" == "RUNNING" ]] && return | ||
| sleep 0.1 | ||
| done | ||
| done | ||
| die "container did not start" | ||
| [[ -z "$detail" ]] || printf '%s\n' "$detail" >&2 | ||
|
Comment on lines
+81
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Preserve startup diagnostics across attempts.
🤖 Prompt for AI Agents |
||
| die "container did not start after 3 verified attempts" | ||
| } | ||
| wait_for_guest_network() { | ||
| local name="$1" attempt | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 8903
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 195
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 195
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 201
🌐 Web query:
lxc-start daemonized exit code socket response still starting RUNNING state polling behavior💡 Result:
When a container is started with lxc-start in daemonized mode, LXC employs a specific synchronization mechanism to ensure the caller can reliably detect when the container has successfully reached the RUNNING state [1][2]. Mechanism Details: 1. Anonymous Socket Pair: To address race conditions where a container's init process might exit before the primary command socket is fully initialized, LXC creates a short-lived anonymous AF_UNIX socket pair (pipe-like behavior) during daemonized initialization [1][2]. 2. Synchronization: The handler uses this socket pair to pass state updates internally. The parent process (the caller) can monitor these sockets to detect the transition to RUNNING [1][2]. 3. State Polling: Tools and callers often interface with LXC's monitor system or command sockets to poll or subscribe to lifecycle state changes (STARTING, RUNNING, STOPPING, etc.) [3][4]. Historically, this relied on lxc-monitord, but modern LXC implementations use native command socket notifications where clients register to receive state change events directly from the container's handler [2][4][5]. 4. Exit Code Handling: If lxc-start fails during the startup phase, it returns specific exit codes to the caller [6]. Generally: - 0-126: Represents the exit code of the application running inside the container [6]. - 128+n: Indicates the application was terminated by signal n [6]. - 255: Indicates an internal LXC error (e.g., failed setup, monitor communication failure) [6]. If a container fails to reach the RUNNING state within a specified timeout (often 5 seconds), the startup process will report a failure to the user, preventing it from incorrectly reporting success for a container that crashed immediately upon launch [2][7]. High-level management tools, such as those used in Proxmox, often implement their own timeout-based polling logic against the monitor socket to ensure that hooks and post-start actions only execute after the container is confirmed to be running [3].
Citations:
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 1048
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 1210
🏁 Script executed:
Repository: gitcommit90/1Helm
Length of output: 1210
scripts/1helm-lxc-runtime:90-94 — Keep the longer polling window before retrying. The 5s wait after a non-zero
lxc-startexit is shorter than the 20s success-path poll, so a daemonized start that lost its state message can still be in flight when the next attempt fires and exhaust all 3 tries early. Use the longer window before retrying.🤖 Prompt for AI Agents