diff --git a/py4web/server_adapters.py b/py4web/server_adapters.py index 59323877b..76028408e 100644 --- a/py4web/server_adapters.py +++ b/py4web/server_adapters.py @@ -121,10 +121,9 @@ def get_workers(opts, default=10): except KeyError: return default - # ---------------------- servers ----------------------------------------------- -def gunicorn(): +def gunicorn(): from gevent import local # pip install gevent gunicorn import threading @@ -132,13 +131,7 @@ def gunicorn(): print("gunicorn: monkey.patch_all() applied") class GunicornServer(ServerAdapter): - """ https://docs.gunicorn.org/en/stable/settings.html """ - - # ./py4web.py run apps -s gunicorn --watch=off --ssl_cert=cert.pem --ssl_key=key.pem -w 6 -L 20 - # ./py4web.py run apps -s gunicornGevent --watch=off --ssl_cert=cert.pem --ssl_key=key.pem -w 6 -L 20 - # time seq 1 5000 | xargs -I % -P 0 curl http://localhost:8000/todo &>/dev/null - - def run(self, app_handler): + def run(self, py4web_apps_handler): from gunicorn.app.base import Application import re @@ -151,10 +144,11 @@ def run(self, app_handler): "keyfile": self.options.get("keyfile", None), "accesslog": None, "errorlog": None, + "config": "sa_config", + # ( 'sa_config', 'GUNICORN_', 'gunicorn.saenv', 'gunicorn.conf.py' ) } if not self.quiet: - level = check_level(self.options["logging_level"]) log_file = get_log_file(out_banner=False) @@ -171,26 +165,34 @@ def run(self, app_handler): ) class GunicornApplication(Application): - def logger_info(self, msg="msg"): + def logger_info(self, msg="its logger_info"): logger and logger.info(str(msg)) - def get_gunicorn_vars(self, env_file="gunicorn.saenv", env_key='GUNICORN_'): + def get_gunicorn_options( + self, + default="gunicorn.conf.py", + env_file="gunicorn.saenv", + env_key="GUNICORN_", + ): def check_kv(kx, vx): - if kx and vx and kx != "bind": + bad_keys = ( + "bind", + "config", + ) + if kx and vx and kx not in bad_keys: if vx.startswith("{") and vx.endswith("}"): - vt = re.sub(r",\s*\}", "}", vx) + vt = re.sub("r'\,\s*\}'", "}", vx) vx = json.loads(vt.replace("'", '"')) if vx == "None": vx = None return kx, vx + self.logger_info(f"gunicorn: Bad {kx}:{vx}") return None, None - result = dict() + if os.path.isfile(default): + return {"use_python_config": default, "config": default} - default_conf = './gunicorn.conf.py' - if os.path.isfile( default_conf ): - result ['use_python_config' ] = default_conf - return result + gu_opts = dict() if os.path.isfile(env_file): try: @@ -200,7 +202,7 @@ def check_kv(kx, vx): line = line.strip() if not line or line.startswith(("#", "[")): continue - for e in ("export ", env_key ): + for e in ("export ", env_key): line = line.replace(e, "", 1) k, v = None, None try: @@ -211,12 +213,12 @@ def check_kv(kx, vx): k, v = check_kv(k, v) if k is None: continue - result[k] = v - if result: - result["config"] = "./" + env_file - return result + gu_opts[k] = v + if gu_opts: + gu_opts["config"] = env_file + return gu_opts except OSError as ex: - self.logger_info(f"gunicorn: cannot read {env_file}; {ex}") + self.logger_info(f"gunicorn: Bad {env_file}; {ex}") for k, v in os.environ.items(): if k.startswith(env_key): @@ -224,39 +226,32 @@ def check_kv(kx, vx): k, v = check_kv(k, v) if k is None: continue - result[k] = v + gu_opts[k] = v - result["config"] = env_key - return result + if gu_opts: + gu_opts["config"] = env_key + return gu_opts def load_config(self): - - gunicorn_vars = self.get_gunicorn_vars() - - # test https://github.com/benoitc/gunicorn/blob/master/examples/example_config.py - for e in ("use_python_config", "use_native_config"): - try: - location = gunicorn_vars[e] - Application.load_config_from_module_name_or_filename( - self, location - ) - self.cfg.set("config", "./" + location) - self.logger_info(f"gunicorn: used {location}") - return - except KeyError: - pass - - sa_config.update(gunicorn_vars) - location = gunicorn_vars["config"] - self.logger_info(f"gunicorn: used {location} {sa_config}") + sa_config.update(self.get_gunicorn_options()) for k, v in sa_config.items(): if k not in self.cfg.settings: continue self.cfg.set(k, v) + if "print_config" in sa_config: + if sa_config["print_config"] == "True": + self.logger_info(sa_config) + self.logger_info(self.cfg) + + for e in ("use_python_config", "use_native_config"): + if e in sa_config: + filename = sa_config[e] + Application.load_config_from_file(self, filename) + def load(self): - return app_handler + return py4web_apps_handler GunicornApplication().run() @@ -266,6 +261,7 @@ def load(self): gunicornGevent = gunicorn + def gevent(): # gevent version 23.9.1