Skip to content
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

Feature/prevent zombie containers #53

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions cli/src/cmd/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export async function testApp({
// build a temp image for test
spinner.start('Building app docker image for test...\n');
const imageId = await dockerBuild({
tag: 'iapp',
abbesBenayache marked this conversation as resolved.
Show resolved Hide resolved
isForTest: true,
progressCallback: (msg) => {
spinner.text = spinner.text + msg;
Expand Down
81 changes: 52 additions & 29 deletions cli/src/execDocker/docker.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,36 +180,59 @@ export async function runDockerContainer({
Env: env,
});

// Start the container
// TODO we should handle abort signal to stop the container and avoid containers running after command is interrupted
await container.start();

// get the logs stream
const logsStream = await container.logs({
follow: true,
stdout: true,
stderr: true,
});
logsStream.on('data', (chunk) => {
// const streamType = chunk[0]; // 1 = stdout, 2 = stderr
const logData = chunk.slice(8).toString('utf-8'); // strip multiplexed stream header
logsCallback(logData);
});
logsStream.on('error', (err) => {
logsCallback('Error streaming logs:', err.message);
});

// Wait for the container to finish
await container.wait();
const stopAndRemoveContainer = async () => {
try {
await container.stop();
await container.remove();
} catch (error) {
throw Error('Error cleaning up container:', error);
}
};

// Check container status after waiting
const { State } = await container.inspect();
const handleInterrupt = async () => {
await stopAndRemoveContainer();
process.exit(0);
};

// Done with the container, remove the container
await container.remove();
process.on('SIGINT', handleInterrupt);
process.on('SIGTERM', handleInterrupt);

return {
exitCode: State.ExitCode,
outOfMemory: State.OOMKilled,
};
try {
// Start the container
await container.start();

// get the logs stream
const logsStream = await container.logs({
follow: true,
stdout: true,
stderr: true,
});
logsStream.on('data', (chunk) => {
const logData = chunk.slice(8).toString('utf-8'); // strip multiplexed stream header
logsCallback(logData);
});
logsStream.on('error', (err) => {
logsCallback('Error streaming logs:', err.message);
});

// Wait for the container to finish
await container.wait();

// Check container status after waiting
const { State } = await container.inspect();

// Done with the container, remove the container
await container.remove();

return {
exitCode: State.ExitCode,
outOfMemory: State.OOMKilled,
};
} catch (error) {
await stopAndRemoveContainer();
throw error;
} finally {
process.off('SIGINT', handleInterrupt);
process.off('SIGTERM', handleInterrupt);
}
}