Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

+ support unix:/socket to gunicorn #847

Merged
merged 3 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion py4web/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2048,7 +2048,7 @@ def run(**kwargs):
'You have not set a dashboard password. Run "%s set_password" to do so.'
% PY4WEB_CMD
)
elif "_dashboard" in Reloader.ROUTES:
elif "_dashboard" in Reloader.ROUTES and (not kwargs['host'].startswith('unix:/')) :
click.echo(
f"Dashboard is at: http{'s' if kwargs.get('ssl_cert', None) else ''}://{kwargs['host']}:{kwargs['port']}/_dashboard"
)
Expand Down
22 changes: 11 additions & 11 deletions py4web/gunicorn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ The gunicorn server starts in the usual way for the py4web

$./py4web.py run apps -s gunicorn --watch=off
$
$./py4web.py run apps -H 'unix:/tmp/p4w.sock' -w 4 -L 10
$
$./py4web.py run apps -s gunicornGevent --watch=off


Expand All @@ -19,11 +21,11 @@ It is possible to use several methods to configure gunicorn options with py4web
Let's show examples (go to py4web root dir)


* set gunicorn options via py4web.py cmd-keys
* set gunicorn options via py4web keys

use: -H, -P, -w, -L, --ssl_cert, --ssl_key, -Q
use: -H, -P, -w, -L, --ssl_cert, --ssl_key , -Q

./py4web.py run apps -s gunicorn --watch=off -w 4 -H 192.168.1.161 -P 9000 -L 20 --ssl_cert=cert.pem --ssl_key=key.pem
./py4web.py run apps -s gunicorn --watch=off -H 192.168.1.161 -P 9000 -L 20 --ssl_cert=cert.pem --ssl_key=key.pem

with -L 10 we can see gunicorn options in server-py4web.log

Expand Down Expand Up @@ -83,8 +85,6 @@ Let's show examples (go to py4web root dir)

# for use python-config-mod_name
# use_python_config=python:mod_name
# or short
# usepy=python:mod_name


* set gunicorn options via python file myguni.conf.py
Expand All @@ -96,10 +96,10 @@ Let's show examples (go to py4web root dir)
.. code:: bash

$ # via env
$export GUNICORN_use_python_config=myguni.conf.py
$export GUNCORN_use_python_config=myguni.conf.py
$
$ # via gunicorn.saenv
$echo use_python_config=myguni.conf.py >> gunicorn.saenv
$echo use_python_config=mmyguni.conf.py >> gunicorn.saenv

::

Expand Down Expand Up @@ -136,7 +136,7 @@ Let's show examples (go to py4web root dir)
$ mkdir mod_name && cp myguni.conf.py mod_name/__init__.py
$
$ # via env
$export GUNICORN_use_python_config=python:mod_name
$export GUNCORN_use_python_config=python:mod_name
$
$ # via gunicorn.saenv
$echo use_python_config=python:mod_name >> gunicorn.saenv
Expand Down Expand Up @@ -193,14 +193,14 @@ Let's show examples (go to py4web root dir)
.. code:: bash

export PY4WEB_LOGS=/tmp
p4w_todo_get() { time seq 1 500 | xargs -I % curl http://localhost:8000/todo &>/dev/null ;}
todotest() { for ((i=0; i < $1; i++)); do p4w_todo_get & done ;}
p4w_srv_test() { time seq 1 500 | xargs -I % curl http://localhost:8000/todo &>/dev/null ;}
gunitest() { for ((i=0; i < 20; i++)); do p4w_srv_test & done ;}

::

$ ./py4web.py run apps -s gunicorn -L 10 --watch=off &

$ todotest 10
$ tguni
$
$ less /tmp/server-py4web.log

Expand Down
39 changes: 27 additions & 12 deletions py4web/server_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,24 +125,37 @@ def get_workers(opts, default=10):
def check_port(host="127.0.0.1", port=8000):
import socket, errno, subprocess

def os_cmd (run_cmd ):
try:
subprocess.run( run_cmd , shell=True, check = True, text=True, )
except subprocess.CalledProcessError :
pass

if host.startswith('unix:/'):
socket_path = host[5:]
if os.path.exists(socket_path):
if port == 0:
os_cmd (f"ls -alFi {socket_path}")
sys.exit(f"can't run gunicorn: {socket_path} exists")
elif port == 1:
os_cmd ("ps -ef | head -1; ps -ef | grep py4web | grep -v grep")
os_cmd (f"ls -alFi {socket_path}")
os_cmd (f"lsof -w {socket_path}")
elif port == 8000:
pass
print (f'gunicorn listening at: {host}')
return

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((host, int(port)))
s.bind((host, int(port) ))
except socket.error as e:
if e.errno == errno.EADDRINUSE:
try:
subprocess.run(
f"command -v lsof >/dev/null 2>&1 && lsof -nPi:{port}",
shell=True,
check=True,
text=True,
)
except subprocess.CalledProcessError:
pass
os_cmd( f"command -v lsof >/dev/null 2>&1 && ps -ef | head -1; ps -ef |"
f" grep py4web | grep -v grep && lsof -nPi:{port}" )
sys.exit(f"{host}:{port} is already in use")
else:
sys.exit(f"{e}\n{host}:{port} cannot be acessed")

s.close()


Expand All @@ -168,8 +181,10 @@ def run(self, app_handler):

logger = None

sa_bind = self.host if self.host.startswith('unix:/') else f"{self.host}:{self.port}"

sa_config = {
"bind": f"{self.host}:{self.port}",
"bind": sa_bind, # f"{self.host}:{self.port}",
"workers": get_workers(self.options),
"certfile": self.options.get("certfile", None),
"keyfile": self.options.get("keyfile", None),
Expand Down
Loading