在代码中重启Django程序

最近在 Qexo 的编写过程中,遇到了一个问题:

如何在完成更新后让程序自动重启?

这个问题困扰了我一段时间,起初使用的是 Django 自带的 AutoReloader,但效果并不佳,经常没有完成文件的完全替换就自动重启,从而导致更新失败。在参考了部分大佬的文章之后,总结出了一个不错的方法。

关闭自动重载

既然我们要把程序的重启完全掌握在自己手中,那么必须要提前关闭好程序的自动重载功能,这一点十分简单,只需要稍微修改启动命令即可

1
python3 manage.py runserver --noreload

只需要加上--noreload参数即可禁用 Django 的 AutoReloader

添加重载代码

结论

先说结论,如果在程序中你需要重载,则需要强制退出子程序并返回“3”作为退出代码,即

1
2
import os
os._exit(3)

这是如何实现的?

经过一番搜索之后,我并没有找到哪个大佬给出了完整的方案(也有可能是我搜索能力较弱),于是在结合了Django源码分析对于 Reloader 的分析给出了这个解决方案

我们观察django.utils.autoreload中有关重启的代码,经过筛选后得到:

1
2
3
4
5
6
7
def restart_with_reloader():
new_environ = {**os.environ, DJANGO_AUTORELOAD_ENV: 'true'}
args = get_child_arguments()
while True:
p = subprocess.run(args, env=new_environ, close_fds=False)
if p.returncode != 3:
return p.returncode

发现 Django 的运行逻辑并不是直接使用主进程,而是创建了一个子进程来执行程序代码,而由原本的进程来实现守护

我们需要重启子线程,就需要让子进程结束,我们观察到如果退出代码不为“3”则结束程序,为“3”则继续运行,重新执行循环来创建子进程,这就是我们需要的

进程自杀的代码为:

1
2
import sys
sys.exit(3) # 3为退出代码

但是很遗憾,这个代码中 sys 库会先抛出一个错误,而这个错误会被 Django 捕获而无法退出,所以我们需要一个更加严厉的退出方法

1
2
import os
os._exit(3)

经过尝试,这个代码完美地符合了我们的要求,主程序遇到“3”作为退出代码后重新创建了一个新的进程,完结撒花

在代码中重启Django程序

http://www.oplog.cn/archives/31002.html

作者

啊不都

发布于

2022-12-24

更新于

2022-12-24

许可协议

CC BY 4.0

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×