background process

This commit is contained in:
bahdotsh
2025-04-06 20:29:44 +05:30
parent 3b5ba27bfa
commit 3abcd2cbf9
3 changed files with 101 additions and 3 deletions

36
.github/workflows/background-test.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Background Process Test
on:
workflow_dispatch:
jobs:
test-background:
runs-on: ubuntu-latest
steps:
- name: Background process with sleep
run: |
echo "Starting background process..."
sleep 5 &
echo "Background process started, PID: $!"
echo "This should complete after the background process"
sleep 1
echo "Foreground process finished, but we should still be waiting for background"
- name: This step should only run after the background process completes
run: echo "If you see this, background process handling works!"
test-multiple-background:
runs-on: ubuntu-latest
steps:
- name: Multiple background processes
run: |
echo "Starting multiple background processes"
sleep 3 &
echo "Started first background process"
sleep 6 &
echo "Started second background process"
echo "Waiting for all background processes to complete"
# The workflow should automatically wait for both processes
- name: Follow-up step
run: echo "All background processes completed!"

View File

@@ -85,6 +85,35 @@ impl ContainerRuntime for DockerRuntime {
// Print detailed debugging info
logging::info(&format!("Docker: Running container with image: {}", image));
// Check if command contains background processes
let has_background = cmd.iter().any(|c| c.contains(" &"));
// If there's a background process, we need to handle it differently
let cmd_vec: Vec<String> = if has_background {
// If the command contains a background process, wrap it in a shell script
// that properly manages the background process and exits when the foreground completes
let mut shell_cmd = Vec::new();
shell_cmd.push("sh".to_string());
shell_cmd.push("-c".to_string());
// Join the original command and add a wait for any child processes
let command_with_wait =
if cmd.len() > 2 && (cmd[0] == "sh" || cmd[0] == "bash") && cmd[1] == "-c" {
// For shell commands, we just need to modify the command string
format!("{} ; wait", cmd[2])
} else {
// Otherwise join all parts and add wait
let cmd_str: Vec<String> = cmd.iter().map(|s| s.to_string()).collect();
format!("{} ; wait", cmd_str.join(" "))
};
shell_cmd.push(command_with_wait);
shell_cmd
} else {
// No background processes, use original command
cmd.iter().map(|s| s.to_string()).collect()
};
// Always try to pull the image first
match self.pull_image(image).await {
Ok(_) => logging::info(&format!("🐳 Successfully pulled image: {}", image)),
@@ -112,8 +141,6 @@ impl ContainerRuntime for DockerRuntime {
platform: None,
});
let cmd_vec: Vec<String> = cmd.iter().map(|s| s.to_string()).collect();
let host_config = HostConfig {
binds: Some(binds),
..Default::default()

View File

@@ -139,6 +139,8 @@ impl ContainerRuntime for EmulationRuntime {
));
}
let has_background = cmd.iter().any(|c| c.contains(" &"));
// For bash/sh with -c, handle specially
if (cmd[0] == "bash" || cmd[0] == "sh")
&& cmd.len() >= 2
@@ -155,6 +157,13 @@ impl ContainerRuntime for EmulationRuntime {
// Get the actual command
let command_str = cmd[idx + 1];
// If we have background processes, add a wait command
let final_cmd = if has_background && !command_str.contains(" wait") {
format!("{{ {}; }} && wait", command_str)
} else {
command_str.to_string()
};
// Create command
let mut command = Command::new(shell);
command.current_dir(&container_working_dir);
@@ -165,7 +174,7 @@ impl ContainerRuntime for EmulationRuntime {
}
// Add the command
command.arg(command_str);
command.arg(final_cmd);
// Set environment variables
for (key, value) in env_vars {
@@ -186,6 +195,32 @@ impl ContainerRuntime for EmulationRuntime {
}
}
if has_background {
// For commands with background processes, use shell wrapper
let mut shell_command = Command::new("sh");
shell_command.current_dir(&container_working_dir);
shell_command.arg("-c");
// Join the original command and add trap for cleanup
let command_str = format!("{{ {}; }} && wait", cmd.join(" "));
shell_command.arg(command_str);
// Set environment variables
for (key, value) in env_vars {
shell_command.env(key, value);
}
let output = shell_command
.output()
.map_err(|e| ContainerError::ContainerExecutionFailed(e.to_string()))?;
return Ok(ContainerOutput {
stdout: String::from_utf8_lossy(&output.stdout).to_string(),
stderr: String::from_utf8_lossy(&output.stderr).to_string(),
exit_code: output.status.code().unwrap_or(-1),
});
}
// For all other commands
let mut command = Command::new(cmd[0]);
command.current_dir(&container_working_dir);