I have a .NET Core service running on a Debian 9, let's call it MyService. At some point this service is running a bash script update.sh
using Process.Start()
with ShellExecute=true
.
This script basically runs apt-get update; apt-get upgrade
.
During package upgrade, MyService process is terminated: update script is terminated as well and apt-get upgrade
is killed as well, leaving inconsistent packages that must be fixed manually.
What I want is that update.sh
is NOT terminated when MyService is terminated.
I tried splitting update.sh
in 2 parts, the first running the second in different ways; I tried starting update2.sh
with setsid
and nohup
but I always get same result.
I tried to execute update2.sh
script in a new bash shell with /bin/bash /c "update2.sh"
, same result.
How do I run a script started from a binary and completely detach from binary process, so I can kill binary while script keeps running?
Here's my environment. MyService is a binary running as a service. update.sh
is started by MyService.
.NET Core code to start shell script, inside MyService binary:
var process = new Process();
process.EnableRaisingEvents = true; // to avoid [defunct] sh processes
process.StartInfo.FileName = "/opt/myservice/update.sh";
process.StartInfo.Arguments = "";
process.StartInfo.UseShellExecute = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit(10000);
if (process.HasExited)
{
Console.WriteLine("Exit code: " + process.ExitCode);
}
else
{
Console.WriteLine("Child process still running after 10 seconds");
}
update.sh:
nohup /opt/myservice/update2.sh > /opt/myservice/update.log &
systemctl stop MyService
update2.sh:
apt-get update >> /opt/myservice/update.log
apt-get -y install --only-upgrade myservice-1.0 >> /opt/myservice/update.log
update2.sh
is never executed because it's terminated when MyService is terminated by update.sh
.
update.sh
returns code 143, it seems it has been killed.
2018-08-16 14:46:14.5215|Running update script: /opt/myservice/update.sh
2018-08-16 14:46:14.5883|Update script /opt/myservice/update.sh returned: 143
UPDATE
I tried following approaches, thanks for suggestions:
- setsid
- disown
- nohup
- screen
- tmux
- unshare
Every approach has same result, termination of all spawned processes. I suspect this is a .NET Core "feature".
UPDATE 2
I discovered that systemctl stop MyService
by default explicitly kills all spawned processes by a service.
https://stackoverflow.com/questions/40898077/systemd-systemctl-stop-aggressively-kills-subprocesses
If I add KillMode=process
to service descriptor, update script is not terminated when service is terminated.
There is NO WAY to escape from PID space for a service started by systemctl
. Every technique used, included the one in accepted answer, does not generate a separate process. Every spawned process is always killed by systemctl stop MyService
unless KillMode=process
is specified.
I ended up creating a separate service MyServiceUpdater
: this service runs the plain updater script without any forking. Since PID space is different, everything works as expected. That was a long ride.
MyServiceUpdater example:
[Unit]
Description=Your Service Updater
After=network.target
[Service]
ExecStart=/path/to/update/script/updatescript.sh
ExecStopPost=
TimeoutStopSec=30
StandardOutput=null
WorkingDirectory=/path/to/service/directory/
KillMode=process
[Install]
WantedBy=multi-user.target
MyServiceUpdater
?