1

I want to start a new instance of my python script when it reaches a specified time during the hour and kill the current instance. The python script starts automatically with boot using a crontab. An infinite while loop reads data. If there is data incoming between minute 59 second 30 and minute 59 second 59, the file gets closed and I want the script to start a new instance of itself with a new process ID and kill the old process. At the moment I am doing this by using

  subprocess.call(['python', '/home/pi/script.py'])
  sys.exit(1)

That starts a new instance of the python script, but the old one is still visible and (it seems) active when I check the processes with top.

Is there a better way to let the program start and kill itself inside the python script?

Another approach using a bash script called by the python script:

#!/bin/sh

PID=`ps -eaf | grep python | grep -v grep | awk '{print $2}'`
if [[ "" !=  "$PID" ]]; then
  echo "killing $PID"
  kill -9 $PID
  sleep 1
  sudo python /home/pi/readserial_V4_RP.py &
  exit 1
fi

But that can't work because the python script end, before the bash script can kill it. I could start the python script without killing python processes, but how can I be sure that no python script is running, before I start the new instance of the python script.

because I have the feeling, when I have more than one same python scripts running, that the first one that was started is doing all the "work" and the others are just in idle...

BallerNacken
  • 305
  • 7
  • 16

3 Answers3

2

Instead of having a process try to restart itself, have a thin parent script that runs the real script. The parent monitor just restarts the script whenever it exits. Since the parent waits until the child has fully exited, you won't have multiple versions running. In a full implementation, the parent holds any system daemon code you need and the child is focused on the task.

This example runs a very boring program that sleeps for the number of seconds specified on the command line

import multiprocessing
import time
import sys
import os
import traceback

def the_real_work_done_here(sleep_time):
    try:
        print(os.getpid(), 'start work')
        time.sleep(sleep_time)
        print(os.getpid(), 'end work')
        exit(0)
    except Exception:
        traceback.print_exc()
        exit(2)

def monitor(sleep_time):
    while 1:
        proc = multiprocessing.Process(target=the_real_work_done_here,
            args=(sleep_time,))
        proc.start()
        proc.join()
        if proc.exitcode != 0:
            print('something went wrong... terminating')
            exit(proc.exitcode)


if __name__ == '__main__':
    try:
        sleep_time = int(sys.argv[1])
        monitor(sleep_time)
    except (KeyError, ValueError):
        print('usage: test.py sleeptime')
        exit(1)
tdelaney
  • 73,364
  • 6
  • 83
  • 116
0

A better way would be to use:

  child = subprocess.Popen(['python','/home/pi/script.py'],shell=True,stdout=subprocess.PIPE)
  output,error = child.communicate()
  print output, error
  sys.exit()
Henin RK
  • 298
  • 1
  • 2
  • 14
  • Thx! I tried it with `shell=True` too, but with the same outcome. I guess the stdout gives me a log where I can see errors if there are some? Or what is it doing? – BallerNacken Mar 06 '16 at 19:29
  • communicate() doesn't return until the process quits. If you want to have control over the process, use poll() and check the content of output periodically. When it's time to kill the process, the outer script can use kill(). – Neil Mar 06 '16 at 19:42
  • @Henin RK Your approach does not seem to work. The current process ends, but the script does not start again. Is it right, that the way I do it at the moment, the old instance of the python script is the parent process and the child can only be killed if the parent ends? I edited a bash script into my question with a different approach and a problem. – BallerNacken Mar 06 '16 at 20:32
0

I know this is an old post, but I needed a way to restart a process but kill the old one. It worked well with creationflags=subprocess.DETACHED_PROCESS.

test.py

from time import sleep
import subprocess
import sys

print("Start")
sleep(1)

print("Start New")
child = subprocess.Popen(['python','test.py'],creationflags=subprocess.DETACHED_PROCESS)
sleep(1)

sys.exit()
GRASBOCK
  • 631
  • 6
  • 16