Python script produces zombie processes only in Docker - python

I have quite complicated setup with
Luigi https://github.com/spotify/luigi
https://github.com/kennethreitz/requests-html
and https://github.com/miyakogi/pyppeteer
But long story short - everything works fine at my local Ubuntu (17.10) desktop, but when run in Docker(18.03.0-ce) via docker-compose(1.18.0) (config version 3.3, some related details here https://github.com/miyakogi/pyppeteer/issues/14) it bloats up with zombie chrome processes spawned from python.
Any ideas why it might happen and what to do with it?

Try installing dumb-init: https://github.com/Yelp/dumb-init (available both in alpine and debian) inside your container and use it as entry point (more reading here: https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/)

Seems like it is because python process is not meant to be a root-level process - the topmost one in the processes tree. It just does not handle zombies properly. So after few hours of struggling I end up with the next ugly docker-compose config entry:
entrypoint: /bin/bash -c
command: "(luigid) &"
Where luigid is a python process. This makes bash a root process which handles zombies perfectly.
Would be great to know a more straightforward way of doing this.

Related

How to restart python script inside bash script every x hours?

I have a quite simple question about starting and restarting python scripts inside an bash script. I hope it's not an duplicate but I didn't find a similiar question. I'm using a bash script which starts a couple of python scripts every time I create a docker container, but It should be probabaly the same on all linux based machines. It's simple as: python3 /mnt/device/script.py &
Now the script will keep running and measure the brightness until the container is stopped. Now I figured out that there are some problems with the sensor library which are brightly discussed on github and still not solved which causes the script to stop every couple of hours. For me It would be enough to have just some command which restarts my script which is running in the background every x hours to avoid that error. So what I'm looking for ist some command which will be like the follwing: python3 for hour=1 /mnt/device/script.py restart &
Thanks in advance!
You can use the Bash timeout command to send a signal to kill the Python script.
restart=""
while true; do
timeout 3600 python3 /mnt/device/script.py $restart
restart="restart"
done &
I'm guessing you don't really need this to run in the background (so maybe take out the &) and that you literally want restart to be passed as an argument after the first time.

Disassociating process pipes from the calling shell

I am trying to use Fabric to send commands which will run many physics simulations (executables) on many different computers which all share the same storage. I would like my script to
ssh into a machine
begin the simulation, for example by running run('nohup nice -n 5 ./interp 1 2 7') (the executable is called interp and run is a function from the Fabric.api library)
detach from the shell and run another simulation on another (or the same) computer.
However I cannot get Fabric to accomplish part 3. It hangs up on the first simulation and doesn't detach until the simulation stops, which defeats the whole point.
My problem, according to the documentation
is that
Because Fabric executes a shell on the remote end for each invocation of run or sudo (see also), backgrounding a process via the shell will not work as expected. Backgrounded processes may still prevent the calling shell from exiting until they stop running, and this in turn prevents Fabric from continuing on with its own execution.
The key to fixing this is to ensure that your process’ standard pipes are all disassociated from the calling shell
The documentation provides 3 suggestions, but it is not possible for me to "use a pre-existing daemonization technique," the computers I have access to do not have screen, tmux, or dtach installed (nor can I install them), and the second proposal of including >& /dev/null < /dev/null in my command has not worked either (as far as I can tell it changed nothing).
Is there another way I can disassociate the process pipes from the calling shell?
The documentation you linked to gives an example of nohup use which you haven't followed all that closely. Merging that example with what you've tried so far gives me something that I, since I don't have Fabric installed, cannot test, but might be interesting to try:
run('nohup nice -n 5 ./interp 1 2 7 < /dev/null &> /tmp/interp127.out &')
Redirect output to /dev/null rather than my contrived output file (/tmp/interp127.out) if you don't care what the interp command emits to its stdout/stderr.
Assuming the above works, I'm unsure how you would detect that a simulation has completed, but your question doesn't seem to concern itself with that detail.

Executing a simple Python script not working with Sidekiq

class SeedWorker
include Sidekiq::Worker
def perform
`python lib/assets/python_scripts/seed.py`
end
end
I am trying to execute this from terminal like so:
bundle exec SeedWorker.perform_async()
I have a Redis server and Sidekiq running as well as a Rails server. The script works fine by itself, but I am wondering if this is even possible. Also Sinatra is running too. Any help would be greatly appreciated.
SeedWorker.perform_async() is not an executable---that will not work. Also, Sidekiq is already running, but it may not have loaded your worker file. Last, Sidekiq just requires Redis. Rails and Sinatra are not related to your problem.
That statement will work in an environment like irb. Alternatively you can use the sidekiq executable:
bundle exec sidekiq -r <path to your worker file>
How about following up the good documentation provided with Sidekiq?

Optionally daemonize a Python process

I am looking into daemonization of my Python script and I have found some libraries that can help: daemonic, daemonize and daemon. Each of them have some issues:
daemonic and daemonize will terminate when they cannot create the PID file. daemonic will not even log or print anything. Looking into the code, they actually call os.exit(). I would like an exception or other error message, so I can fallback to running my code in the foreground.
daemon doesn't even install correctly for Python 3. And seeing the last commit was in 2010, I don't expect any updates soon (if ever).
How can I portably (both Python2 and 3) and optionally (falling back to running in foreground) create a daemonized Python script? Of course I could fallback to using the & operator when starting it, but I would like to implement PEP3143.
I am using two solutions
based on zdaemon
based on supervisor
Both packages are written in Python and are daemonizing anything, what can be run from command line. The requirement is, that the command to be run is running in foreground and not trying to daemonize itself.
supervisor is even part of Linux distributions and even though it comes in a bit outdated version, it is very well usable.
Note, that as it controls general command line driven program, it does not require python version being matched with the controlled code.

Is there Windows analog to supervisord?

I need to run python script and be sure that it will restart after it terminates. I know that there is UNIX solution called supervisord. But unfortunately server where my script has to be run is on Windows. Do you know what tool can be useful?
Thanks
Despite the big fat disclaimer here, you can run Supervisor with Cygwin in Windows; it turns out that Cygwin goes a long way to simulate a Posix environment, so well that in fact supervisord runs unchanged. There is no need to learn a new tool, and you will even save quite a bit of work if you need to deploy a complicated project across multiple platforms.
Here's my recipe:
If you have not done it yet, install Cygwin. During the installation process, select Python.
From the Cygwin terminal, install virtualenv as usual.
Create a virtualenv for supervisord, and then install as usual:
pip install supervisord
Configure supervisord in the usual way. Keep in mind that supervisord will be running with Cygwin, so you better use paths the Cygwin way (C:\myservers\project1 translates to /cygdrive/c/myservers/project1 in Cygwin).
Now you probably want to install supervisord as a service. Here's how I do it:
cygrunsrv --install supervisord --path /home/Administrator/supervisor/venv/bin/python --args "/home/Administrator/supervisor/venv/bin/supervisord -n -c /home/Administrator/supervisor/supervisord.conf"
Go to the Windows service manager and start the service supervisord that you just installed.
Point 5 installs supervisord as a Windows service, so that you can control it (start/stop/restart) from the Windows service manager. But the things that you can do with supervisorctl work as usual, meaning that you can simply deploy your old configuration file.
You likely want to run your script as a Windows Service. To do so you'll need the python-win32 library. This question has a good description of how you go about doing this, as well as a bunch of links to other related resources. This question may also be of use.
A Windows Service is how you want to wrap up any script that needs to run continuously on Windows. They can be configured to automatically start on boot, and handle failures. Nothing is going to stop anyone from killing the process itself, but to handle that potential situation, you can just create a bat file and use the sc command to poll the service to see if it is running and if not restart the service. Just schedule the bat file to run every 60 seconds (or whatever is reasonable for your script to potentially be down).
If you want a supervisord-like process manager that runs on most posix OS and is Python-based like supervisord, then you should look at honcho which is a Python port of foreman (Ruby-based):
http://pypi.python.org/pypi/honcho/
It works great on mac, linux but (actually) not yet windows... (editing my initial answer where I had said optimistically it was already working on Windows based on a pull request that has been discarded since)
There is a fork that provides Windows support here https://github.com/redpie/honcho
and some work in progress to support Windows here https://github.com/nickstenning/honcho/issues/28 ... at least it could become a possible solution in a near future.
There is also a foreman fork to support Windows here: https://github.com/ddollar/foreman-windows that may be working for you, though I never tried it.
So for now, a Windows service might be your best short term option.
supervisor for windows worked for us on python27 - 32 bit. I had to install pypiwin32 and pywin32==223.
As it is an old question with old answers I will update it with latest news:
There is a supervisor-win project that claims to support supervisor on Windows.
No, supervisord is not supported under Windows.
BUT what you can do is, to restart it automatically from a wrapper script:
#!/usr/bin/python
from subprocess import Popen
file_path = " script_to_be_restarted.py"
args_as_str = " --arg1=woop --arg2=woop"
while True:
print("(Re-)Start script %s %s" % (file_path, args_as_str))
p = Popen("python " + file_path + args_as_str, shell=True)
p.wait()

Categories