korki696
korki696

Reputation: 103

subprocess.popen detached from master (Linux)

I am trying to open a subprocess but have it be detached from the parent script that called it. Right now if I call subprocess.popen and the parent script crashes the subprocess dies as well.

I know there are a couple of options for windows but I have not found anything for *nix.

I also don't need to call this using subprocess. All I need is to be able to cal another process detached and get the pid.

Upvotes: 3

Views: 6710

Answers (5)

jaksco
jaksco

Reputation: 531

This might do what you want:

def cmd_detach(*command, **kwargs) -> subprocess.CompletedProcess:
    # https://stackoverflow.com/questions/62521658/python-subprocess-detach-a-process
    # if using with ffmpeg remember to run it with `-nostdin`
    stdout = os.open(os.devnull, os.O_WRONLY)
    stderr = os.open(os.devnull, os.O_WRONLY)
    stdin = os.open(os.devnull, os.O_RDONLY)

    command = conform(command)
    if command[0] in ["fish", "bash"]:
        import shlex
        command = command[0:2] + [shlex.join(command[2:])]
    subprocess.Popen(command, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=True, start_new_session=True, **kwargs)
    return subprocess.CompletedProcess(command, 0, "Detached command is async")

On Windows you might need

CREATE_NEW_PROCESS_GROUP = 0x00000200
DETACHED_PROCESS = 0x00000008
creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP

instead of start_new_session=True

Upvotes: 1

jobeard
jobeard

Reputation: 129

fork the subprocs using the NOHUP option

Upvotes: 0

korki696
korki696

Reputation: 103

I managed to get it working by doing the following using python-daemon:

process = subprocess.Popen(["python", "-u", "Child.py"])
    time.sleep(2)
    process.kill()

Then in Child.py:

with daemon.DaemonContext():
    print("Child Started")
    time.sleep(30)
    print "Done"
    exit()

I do process.kill() because otherwise it creates a defunct python process. The main problem I have now is that the PID that popen returns does not match the final pid of the process. I can get by this by adding a function in Child.py to update a database with the pid.

Let me know if there is something that I am missing or if this is an ok method of doing this.

Upvotes: 0

flaschbier
flaschbier

Reputation: 4175

With linux, it's no issue at all. Just Popen(). For example, here is a little dying_demon.py

#!/usr/bin/python -u
from time import sleep
from subprocess import Popen
print Popen(["python", "-u", "child.py"]).pid
i = 0
while True:
    i += 1
    print "demon: %d" % i
    sleep(1)
    if i == 3:
        i = hurz # exception

spinning off a child.py

#!/usr/bin/python -u
from time import sleep
i = 0
while True:
    i += 1
    print "child: %d" % i
    sleep(1)
    if i == 20:
        break

The child continues to count (to the console), while the demon is dying by exception.

Upvotes: 3

Filip Malczak
Filip Malczak

Reputation: 3204

I think this should do the trick: https://www.python.org/dev/peps/pep-3143/#reference-implementation

You can create daemon which will call your subprocess, passing detach_process=True.

Upvotes: 1

Related Questions