Django 模型中的 Long 运行 后台线程

Long running background thread in Django model

我对 Python 和 Django 还很陌生,如果有更好的方法,请告诉我。我想要做的是让每个设备(从 models.Model 继承)启动一个长 运行ning 后台线程,不断检查该设备的运行状况。然而,当我 运行 我的代码时,它似乎不像守护进程那样执行,因为服务器缓慢并且不断超时。这个后台线程将(在大多数情况下)运行 程序的生命周期。

下面是我的代码的简化版本:

class Device(models.Model):
    active = models.BooleanField(default=True)
    is_healthy = models.BooleanField(default=True)
    last_heartbeat = models.DateTimeField(null=True, blank=True)

    def __init__(self, *args, **kwargs):
        super(Device, self).__init__(*args, **kwargs)
        # start daemon thread that polls device's health
        thread = Thread(name='device_health_checker', target=self.health_checker())
        thread.daemon = True
        thread.start()


    def health_checker(self):
        while self.active:
            if self.last_heartbeat is not None:
                time_since_last_heartbeat = timezone.now() - self.last_heartbeat
                self.is_healthy = False if time_since_last_heartbeat.total_seconds() >= 60 else True
                self.save()
                time.sleep(10)

这似乎是对线程的一种非常简单的使用,但每次我搜索解决方案时,建议的方法是使用芹菜,这对我来说似乎有点过分了。有没有办法让它工作而不需要芹菜之类的东西?

当您开始使用开发环境时,设备数量可能非常少。因此,当您进行测试时,线程数可能是两位数。

但随着设备数量的增加,即使代码可以正常工作,这个线程问题也会很快变得难以为继。因此,使用带有 celery beat 的芹菜是更好的方法。

还要考虑到您是 Django 和 Python 的新手,尝试在此基础上掌握线程会增加更多的复杂性。最后使用 celery 会更简单、更整洁。

正如@knbk 在评论中提到的,"Every time you query for devices, a new thread will be created for each device that is returned"。这是我原来忽略的。

但是,我能够使用作为 Django 应用程序启动的单个后台线程解决我的问题。这是一种比添加第 3 方库(如 Celery)更简单的方法。

class DeviceApp(AppConfig):
    name = 'device_app'

    def ready(self):
        # start daemon thread that polls device's health
        thread = Thread(name='device_health_checker', target=self.device_health_check)
        thread.daemon = True
        thread.start()

def device_health_check(self):
    while (true):
        for device in Device.objects.get_queryset():
            if device.last_heartbeat is not None:
                time_since_last_heartbeat = timezone.now() - device.last_heartbeat
                device.is_healthy = False if time_since_last_heartbeat.total_seconds() >= 60 else True
                device.save()
        time.sleep(10)