Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to run flask in a single process? (to work around apparent issue with ipdb & Docker ttys)

I have a flask app which I am running like this:

flask run --host=0.0.0.0

When I look at the process list I see this:

UID        PID  PPID  C STIME TTY          TIME CMD root         1     0  0 23:48 pts/0        00:00:00 /bin/sh -c flask run --host=0.0.0.0 root         6     1  1 23:48 pts/0        00:00:01 /usr/local/bin/python /usr/local/bin/flask run --host=0.0.0.0 root         8     6  3 23:48 pts/0        00:00:02 /usr/local/bin/python /usr/local/bin/flask run --host=0.0.0.0 

Three processes.

If I run using --without-threads I also the same three processes:

UID        PID  PPID  C STIME TTY          TIME CMD root         1     0  0 00:28 pts/0    00:00:00 /bin/sh -c flask run --host=0.0.0.0 --without-threads root         6     1  2 00:28 pts/0    00:00:02 /usr/local/bin/python /usr/local/bin/flask run --host=0.0.0.0 --without-threads root         8     6  4 00:28 pts/0    00:00:04 /usr/local/bin/python /usr/local/bin/flask run --host=0.0.0.0 --without-threads 

Is there a way to somehow run flask as a single process?

Motivation

The flask app in question is running inside a docker container. I would like to be able to set breakpoints using ipdb.

I have observed that if I set this in my docker-compose file:

    stdin_open: true     tty: true 

and run, instead of a flask app, a simple single-process python app...

$ docker exec -it bug_demo_bug_demo_1 bash root@98245482089b:/opt/bug_demo/bug_demo# ps -ef UID        PID  PPID  C STIME TTY          TIME CMD root         1     0  0 00:41 pts/0    00:00:00 /bin/sh -c python app.py root         7     1 20 00:41 pts/0    00:00:00 python app.py 

... and attach to the container while the app is at a breakpoint, I am able to drop into ibpd and use it normally – arrow keys and tab completion work properly.

But when I try do the same with the flask app (attach to the container while the app is waiting in a breakpoint), things do not work correctly.

Either I disable tty: true in docker-compose.yml, and can use use ipdb but without arrow keys and tab completion, OR I leave tty: true in place, but then cannot really use ipdb at all, b/c it appears the tty is attached to all three flask processes, causing everything other than single character commands to get garbled. (Although I can see with this setup that arrow keys and tab completion work.)

All of this leads me to believe that if I can find a way to run my flask app as a single process, I will be able to attach to the docker container and use ipdb as desired.

Is there some way to do this?

Update: problem manifests during startup, not during request handling

Upon further examination, I see that this problem only manifests during "startup" code. ex: if the breakpoint is inside the create_app function.

If the breakpoint is inside a request handler method, or code called from a request handler, everything works as expected.

Using exec reduces the process count from three to two (the root process gets replaced by the first worker), but the problem still manifest for breakpoints inside create_app.

Running flask with --no-reload makes the second worker go away, so process count can then be forced to one or two, by then not using or using exec. Running with --no-reload is not ideal for my use case, but it does make the problem go away, even for breakpoints in create_app.

For my purposes, I can live with the limitation of ipdb only playing nice with the terminal inside request handlers -- I don't expect a great need to run the debugger from startup code. (But I will still accept an answer & happily award the bounty, if anyone can explain exactly what is happening in the startup-code breakpoint case, and why the problem does not manifest in the request-handler breakpoint case.)

Based on the --no-reload finding, it does feel like the underlying flakiness is somehow related to the TTY being "shared" by the request handling process and the code-reloading process.

Flask & Docker Version Info

ipdb> flask.__version__ '1.0.3' 
$ docker version Client: Docker Engine - Community  Version:           18.09.2  API version:       1.39  Go version:        go1.10.8  Git commit:        6247962  Built:             Sun Feb 10 04:12:39 2019  OS/Arch:           darwin/amd64  Experimental:      false  Server: Docker Engine - Community  Engine:   Version:          18.09.2   API version:      1.39 (minimum version 1.12)   Go version:       go1.10.6   Git commit:       6247962   Built:            Sun Feb 10 04:13:06 2019   OS/Arch:          linux/amd64   Experimental:     false 
$ docker info Containers: 22  Running: 3  Paused: 0  Stopped: 19 Images: 362 Server Version: 18.09.2 Storage Driver: overlay2  Backing Filesystem: extfs  Supports d_type: true  Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins:  Volume: local  Network: bridge host macvlan null overlay  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: 9754871865f7fe2f4e74d43e2fc7ccd237edcbce runc version: 09c8266bf2fcf9519a651b04ae54c967b9ab86ec init version: fec3683 Security Options:  seccomp   Profile: default Kernel Version: 4.9.125-linuxkit Operating System: Docker for Mac OSType: linux Architecture: x86_64 CPUs: 2 Total Memory: 3.855GiB Name: linuxkit-025000000001 ID: ZAK2:V2VU:IZFF:6MQQ:IFJB:2ZKY:VHA5:CSO3:VXQQ:UK6C:O3I7:S3ZU Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): true  File Descriptors: 59  Goroutines: 89  System Time: 2019-07-28T14:00:38.3184372Z  EventsListeners: 2 HTTP Proxy: gateway.docker.internal:3128 HTTPS Proxy: gateway.docker.internal:3129 Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries:  127.0.0.0/8 Live Restore Enabled: false Product License: Community Engine 
$ docker-compose --version docker-compose version 1.23.2, build 1110ad01 
like image 720
billc Avatar asked Jul 26 '19 01:07

billc


People also ask

Why does running the flask dev server run itself twice?

The reason for this is that due to how the reload mechanism works there are some bizarre side-effects (like executing certain code twice...)

How do I run a flask in the background?

Make sure, you close the terminal and not press Ctrl + C. This will allow it to run in background even when you log out. To stop it from running , ssh in to the pi again and run ps -ef |grep nohup and kill -9 XXXXX where XXXX is the pid you will get ps command.

How does a flask run work?

The flask run method is the newest solution and is recommended by the Flask project. The flask command is added to your virtual environment when you install the Flask package. It comes out of the box with three commands: (venv) $ flask --help Usage: flask [OPTIONS] COMMAND [ARGS]...

How do I run a flask on a local machine?

To install flask, simply type in pip install flask in your computer terminal/command line. Once you have made sure flask is installed, simply run the hello.py script. Once you run the script, the website should now be up and running on your local machine, and it can be viewed by visiting localhost:5000 in your browser.


1 Answers

To make flask run in single processer use the below

if __name__ == '__main__':     app.run(threaded=False, processes=1) 
like image 197
Alivx Avatar answered Sep 19 '22 18:09

Alivx