From bcb0e61bfc174d1e8a1a2aa98d3af02935fb6ac6 Mon Sep 17 00:00:00 2001 From: "girish@cloudron.io" Date: Thu, 21 Jan 2016 17:40:41 -0800 Subject: [PATCH] Kill child processes On Unix, child processes are not killed when parent dies. Each process is part of a process group (pgid). When pgid == pid, it is the process group leader. node creates child processes with the parent as the group leader (detached = false). You can send a signal to entire group using kill(-pgid), as in, negative value in argument. Systemd can be made to do this by setting the KillMode=control-group. Unrelated: Process groups reside inside session groups. Each session group has a controlling terminal. Only one process in the session group has access to the terminal. Process group is basically like a bash pipeline. A session group is the entire login session with only one process having terminal access at a time. Fixes #543 --- baseimage/initializeBaseUbuntuImage.sh | 3 ++- installer/src/installer.js | 1 + setup/container/systemd/box.service | 3 ++- src/taskmanager.js | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/baseimage/initializeBaseUbuntuImage.sh b/baseimage/initializeBaseUbuntuImage.sh index a75463430..47f7982c3 100644 --- a/baseimage/initializeBaseUbuntuImage.sh +++ b/baseimage/initializeBaseUbuntuImage.sh @@ -227,7 +227,8 @@ Description=Cloudron Installer Type=idle ExecStart="${INSTALLER_SOURCE_DIR}/src/server.js" Environment="DEBUG=installer*,connect-lastmile" ${provisionEnv} -KillMode=process +; kill any child (installer.sh, retire.sh) as well +KillMode=control-group Restart=on-failure [Install] diff --git a/installer/src/installer.js b/installer/src/installer.js index eb6a6ac7f..2459f926b 100644 --- a/installer/src/installer.js +++ b/installer/src/installer.js @@ -36,6 +36,7 @@ util.inherits(InstallerError, Error); InstallerError.INTERNAL_ERROR = 1; InstallerError.ALREADY_PROVISIONED = 2; +// system until file has KillMode=control-group to bring down child processes function spawn(tag, cmd, args, callback) { assert.strictEqual(typeof tag, 'string'); assert.strictEqual(typeof cmd, 'string'); diff --git a/setup/container/systemd/box.service b/setup/container/systemd/box.service index 8d6ddc755..faf136a0d 100644 --- a/setup/container/systemd/box.service +++ b/setup/container/systemd/box.service @@ -9,7 +9,8 @@ WorkingDirectory=/home/yellowtent/box Restart=always ExecStart=/usr/bin/node --max_old_space_size=150 /home/yellowtent/box/box.js Environment="HOME=/home/yellowtent" "USER=yellowtent" "DEBUG=box*,connect-lastmile" "BOX_ENV=cloudron" "NODE_ENV=production" -KillMode=process +; kill apptask processes as well +KillMode=control-group User=yellowtent Group=yellowtent MemoryLimit=200M diff --git a/src/taskmanager.js b/src/taskmanager.js index 2b5fcf29a..89e4e8860 100644 --- a/src/taskmanager.js +++ b/src/taskmanager.js @@ -92,6 +92,7 @@ function startAppTask(appId) { return; } + // when parent process dies, apptask processes are killed because KillMode=control-group in systemd unit file gActiveTasks[appId] = child_process.fork(__dirname + '/apptask.js', [ appId ]); var pid = gActiveTasks[appId].pid;