【问题标题】:Django manage.py runserver graceful reloadingDjango manage.py runserver 优雅重载
【发布时间】:2019-12-29 00:36:26
【问题描述】:

我正在开发一个集成了网络摄像头和 OpenCV 的 Django 项目。对于网络摄像头访问,我使用以下代码。如果我使用Ctrl + C 结束正在运行的服务器,可以释放网络摄像头,但如果服务器在代码更改后重新加载,则网络摄像头无法正常释放,因此将不可用。如何检测热重载以便正确关闭网络摄像头?

我知道禁止热重新加载的选项,但这很不舒服。有什么我可以通过编程实现的选项吗?

class VideoCamera(object):
    def __init__(self):
        self.video = None

    def __del__(self):
        if self.video is not None and self.video.isOpened():
            self.video.release()

    def get_frame(self):
        try:
            self.video = cv2.VideoCapture(0)
            success, image = self.video.read()
            self.video.release()
            ret, jpeg = cv2.imencode('.jpg', image)
            return jpeg.tobytes()
        except (SystemExit, KeyboardInterrupt, Exception) as e:
            self.video.release()
            raise e

【问题讨论】:

标签: django opencv


【解决方案1】:

一些想法

1) 您可以连接file_change 信号,该信号在重新加载之前在文件更改时触发

https://github.com/django/django/blob/9386586f31b8a0bccf59a1bff647cd829d4e79aa/django/utils/autoreload.py#L24

def notify_file_changed(self, path):
    results = file_changed.send(sender=self, file_path=path)
    logger.debug('%s notified as changed. Signal results: %s.', path, results)
    if not any(res[1] for res in results):
        trigger_reload(path)

2) 简单的猴子补丁触发重载功能并注入网络摄像头关闭代码

https://github.com/django/django/blob/9386586f31b8a0bccf59a1bff647cd829d4e79aa/django/utils/autoreload.py#L221

【讨论】:

    【解决方案2】:

    如果你的类是一个单例,它看起来是,在它的文件中创建你的类的一个实例,然后添加 Django 信号处理程序来执行清理。由于使用__del__ 通常是not recommended,我建议您添加一个信号(系统信号,如SIGINT/ctrl+C)处理程序,将其作为Django 信号转发。这意味着,从django.utils.autoreloadSIGINT 收听file_changed

    要在其他文件中使用单例,请使用from my_app.singleton import my_singleton 导入它。

    # my_app/singleton.py
    
    class MySingleton:
        def __init__(self):
            """Init code here"""
    
        def close(self):
            """Shutdown code here"""
    
    my_singleton = MySingleton()
    

    然后,为您的应用注册信号处理程序。这是标准的 AFAIK。

    # my_app/apps.py
    from django.apps import AppConfig
    
    
    class MyAppConfig(AppConfig):
        name = "my_app"
    
        def ready(self):
            import my_app.signals
    

    信号处理程序文件本身,导入单例并在关机时关闭它。这在 file_changed 和 SIGINT 上调用。

    # my_app/signals.py
    from django.dispatch import receiver
    from django.utils.autoreload import file_changed
    from my_app.signal_definitions import system_shutdown_signal
    from my_app.singleton import my_singleton
    
    @receiver(file_changed)
    @receiver(system_shutdown_signal)
    def my_shutdown_handler(sender, **kwargs):
        my_singleton.close()
    

    注册一个处理程序以捕获来自系统的 SIGINT 信号。

    # my_app/__init__.py
    import signal
    import sys
    
    from iot.signal_definitions import system_shutdown_signal
    
    
    def _forward_to_django_shutdown_signal(signal, frame):
        print(f"Shutting down Django {sys.argv}")
        system_shutdown_signal.send("system")
        sys.exit(0)
    
    
    signal.signal(signal.SIGINT, _forward_to_django_shutdown_signal)
    

    用于传播系统 SIGINT 信号的 Django 信号。

    # my_app/signal_definitions.py
    from django.dispatch import Signal
    
    system_shutdown_signal = Signal()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-23
      • 2014-02-17
      • 1970-01-01
      • 1970-01-01
      • 2013-08-23
      • 2018-06-01
      相关资源
      最近更新 更多