Python Forum
How do you wait for a daemon to reach a certain state with subprocess.popen()?
Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How do you wait for a daemon to reach a certain state with subprocess.popen()?
#1
Hello All,
I am trying to launch a daemon using subprocessor.Popen(), the daemon runs for about 30 seconds until it reaches a steady state.  My question is how can I determine it has reached the steady state before continuing my python execution?  
The daemon stops printing to screen once it has reached a steady state.  
Any help is appreciated, I don't have to use Popen if there are other better options.
Thanks!

try:
     p = subprocess.Popen(exe_path)
     #wait until it reaches steady state
     do_stuff()
except subprocess.CalledProcessError as e:
    print(e)
finallly:
    p.kill()
Reply
#2
You could read the stdout of the process, and when there's nothing left to read you know it's "ready"?

Here's some fake code I didn't test:
proc = subprocess.Popen(exe_path, stdout=subprocess.PIPE)
while proc.stdout.peek():
   output = proc.stdout.read()
# no more output (or we read input before the process wrote anything) 
Reply
#3
(Jul-07-2017, 04:07 PM)nilamo Wrote: You could read the stdout of the process, and when there's nothing left to read you know it's "ready"?

Here's some fake code I didn't test:
proc = subprocess.Popen(exe_path, stdout=subprocess.PIPE)
while proc.stdout.peek():
   output = proc.stdout.read()
# no more output (or we read input before the process wrote anything) 

Thanks, I tried this and it doesn't seem to exit the while loop, looks like .read() hangs waiting for a response when none is given (maybe waiting for EOF or something?). I tried 'continue' instead of .read() and it still hung. So maybe even .peek() is being problematic.

Sorry just realized .read() has to be used (or .readline()). Still hanging, its like it isn't finishing the .read()
Reply
#4
All posted code is only for Python 3.

proc.stdout.read() blocks until EOF has been reached. This happens, when the process has been closed.
proc.stdout.readline() blocks until a new line is in the buffer.

It tested it with a shell script. I am not sure if it behaves like your daemon. It's different because the shell forks child processes.

daemon-sim.sh:
#!/bin/bash
sleep 4
echo "Running daemon..."
sleep 1
echo "Deamon is running now."
while true; do sleep 5; echo "`date`"; done
import subprocess
import re


def wait_for_daemon(path, args, ready_line_regex, shell=False):
   cmd = [path] + args
   proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE)
   while True:
       line = proc.stdout.readline() # returns bytes
       if ready_line_regex.search(line):
           break
   return proc


running_regex = re.compile(rb'Running daemon') # Using raw binary strting for regex
proc = wait_for_daemon('./daemon-sim.sh', [], running_regex, shell=True)
# don't use shell=True in your case, it's unsafe
I think this may solve your problem. But pay attention, if your daemon process is logging to stdout,
it's added to your memory. To prevent huge memory consumption, you should have a task, which is reading proc.stdout.
In most cases logging of daemons happens to stderr. In this case you're not redirecting stderr to somewhere. You'll see them in
your shell or if the daemon has a logging function, it logs to a file.

Good shell citizens are logging errors to stderr and data is written to stdout. A daemon process should not
log errors to stdout. But sometimes they do.

The solution above starts the process and redirect stdout to the PIPE.
Inside the while loop proc.stdout.readline() is called, which blocks until there is a new line.
When the check is True, the while loop is stopped (break) and the function returns proc.

A solution without regex:
import subprocess


def wait_for_daemon(path, args, ready_string, shell=False):
   cmd = [path] + args
   proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE)
   while True:
       line = proc.stdout.readline() # returns bytes
       if ready_string in line:
           break
   return proc


running_string = b'Running daemon' # Using binary string
proc = wait_for_daemon('./daemon-sim.sh', [], running_string, shell=True)
# don't use shell=True in your case, it's unsafe
You can also set encoding in Popen to 'utf-8' or other encoding, which depends on your daemon.
If you set the encoding, stdout.readline() returns a str and not bytes. If you don't set encoding, you'll receive bytes.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Information subprocess.Popen() suddenly giving me grief? davecotter 3 604 Dec-13-2023, 10:49 PM
Last Post: davecotter
  Use subprocess.Popen and time.sleep chucky831 2 1,934 Aug-11-2022, 07:53 PM
Last Post: carecavoador
  Wait til a date and time KatManDEW 2 1,413 Mar-11-2022, 08:05 PM
Last Post: KatManDEW
  wait for the first of these events Skaperen 4 1,929 Mar-07-2022, 08:46 PM
Last Post: Gribouillis
  how to do a two-way wait Skaperen 2 1,258 Mar-04-2022, 02:31 AM
Last Post: Skaperen
  Subprocess.Popen() not working when reading file path from csv file herwin 13 14,949 May-07-2021, 03:26 PM
Last Post: herwin
  Did subprocess.Popen() causes main routine to pause stdout? liudr 4 3,616 May-04-2021, 08:58 PM
Last Post: liudr
  disable subprocess.popen prompt echo paul18fr 1 1,996 Feb-04-2021, 02:50 AM
Last Post: Larz60+
  I have an index error inline 76 but I write the program in a way that cant reach tha abbaszandi 2 2,052 Nov-13-2020, 07:43 AM
Last Post: buran
  how to pass the interactive string to Popen subprocess maiya 1 1,873 Sep-18-2020, 09:36 PM
Last Post: Larz60+

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020