Gunicorn 动态反映更改的代码
Posted
技术标签:
【中文标题】Gunicorn 动态反映更改的代码【英文标题】:Gunicorn reflect changed code dynamically 【发布时间】:2021-02-19 09:35:04 【问题描述】:我正在开发一个 django Web 应用程序,用户可以在应用程序本身中通过 UI 使用 ace editor 修改某些类的代码(想象成 gitlab/github,您可以在其中在线更改代码)。但是这些课程有时是由 django 和 celery worker 运行的。
保存代码更改后,由于 gunicorn,django 不会选择更改,但可以正常使用 celery,因为它的过程不同。 (使用 runserver
在本地运行它可以正常工作,并且 django 和 celery 都会选择更改)。
有没有办法让 gunicorn 反映包含类的某个目录的更改而不重新加载整个应用程序?如果需要重新装载,有没有办法在不停机的情况下一个接一个地重新装载 gunicorn 的工人?
gunicron 命令:
/usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app
wsgi 配置文件:
import os
import sys
from django.core.wsgi import get_wsgi_application
app_path = os.path.abspath(os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.pardir))
sys.path.append(os.path.join(app_path, 'an_application'))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
application = get_wsgi_application()
【问题讨论】:
这应该是一个 200+ 赏金问题。 看看这个帖子superuser.com/questions/181517/…它可能对你有用 事实上gunicorn
有一个选项 --reload
(@see docs.gunicorn.org/en/latest/settings.html#debugging) 可以重新加载代码更改但是它不是用于生产环境。
@Coderji 看看这个类似的项目djangosites.org/s/django-visual-herokuapp-com,但不幸的是它不会在代码更改时自动重新加载项目。无论如何,它可能会帮助您改进您的项目
您可以将代码块写入文件,然后使用 python 的eval()
在运行时运行它。这不是一个真正安全的操作,但应该可以完成这项工作。
【参考方案1】:
重新加载选项是“用于开发”。没有强烈的措辞说你不应该在生产中使用它。您不应该在生产中使用它的原因是因为人们打错字,更改一个文件,可能需要对其他文件进行其他一些更改等等。因此,您可以使您的网站无法访问,然后您就没有工作应用程序再次修复它。
对于开发人员来说,这没问题,因为您可以查看 shell 中的日志/输出并重新启动它。这就是为什么@Krzysztof 的建议是最好的。将代码更改推送到您的 repo,使其通过 CI/CD 并切换 pod。如果 CI 失败,那么 CD 就不会发生,所以你很好。
当然,对于问答网站来说,这个范围太大了。
【讨论】:
谢谢你的回答,我会给观看文件一个机会,虽然我试图找到另一个解决方案。目前实现的方式是push到git,通过CI/CD进行更新。但是每两周(在每个 sprint 之前)将应用程序发布到生产环境中,对于这类课程,我们不能等待这么长时间。并且樱桃选择更新推送到发布分支并不是我们目前发现的一个好方法。因此,客户建议即时修改这些类。 如果这些是错误修复,那么请教您的团队使用错误修复分支,从当前生产分支分支。我不明白为什么有些课程需要在短时间内因为其他原因而改变。你在使用choices
,你应该在哪里使用外键?你能举一个需要频繁更新的模型的例子吗?
应用程序托管 ML 模型,每个模型都有自己的脚本,用于每个模型的前/后处理。尽管模型调用可以泛化和上传,但不能完全泛化处理部分。另外,算法不全是python,它们可以是C++和matlab,“代码数据科学家改变”可以调用matlab运行时或Boost类。最终,我们对每个模型进行版本控制,新版本可能包含他们需要更新的新处理,但您仍然需要保留旧版本,以免请求者破坏他们的管道。【参考方案2】:
为什么不将代码保存在单独的文本文件或数据库中,相关方法可以简单地将代码作为字符串动态加载并使用exec()
执行它?
假设您有一个功能function1
,可以由用户编辑。当用户提交更改时,处理输入(分离出函数,以便您知道哪个函数有什么定义),并将它们全部单独保存,如function1
、function2
等,在数据库或文本文件中作为字符串。
您需要执行function1
,只需加载您保存的值并使用exec
执行代码。
这样,您无需重新加载 gunicorn
,因为所有工作人员将始终在运行时获取更新的函数定义!
以下内容:
def function1_original():
# load function definition
f = open("function1.txt", "r")
# execute the string
exec(f.read()) # this will just load the function definition
function1() # this will execute the user defined function
所以用户将定义:
def function1():
# user defined code
# blah blah
...
【讨论】:
【参考方案3】:我可以通过将 python 脚本的扩展名更改为 .py
以外的任何内容来解决此问题
然后我使用以下函数加载了这些文件:
from importlib import util
from immportlib.machinary import SourceFileLoader
def load_module(module_name, modele_path):
module_path = path.join(path.dirname(__file__), "/path/to/your/files.anyextension".format(module_name))
spec = util.spec_from_loader(module_name,
SourceFileLoader(module_name, module_path))
module = util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
在这种情况下,Gunicorn 不会将它们加载到 RAM 中,我能够即时应用更改,而无需应用 eval
或 exec
函数。
【讨论】:
以上是关于Gunicorn 动态反映更改的代码的主要内容,如果未能解决你的问题,请参考以下文章
Heroku 上带有 gunicorn 服务器的 Django 项目不提供静态文件
为啥代码更改时自动重新加载仅用于使用 Gunicorn 进行调试?