我正在尝试从 Django 中 运行 一个无休止的工作线程(守护进程)
I am trying to run an endless worker thread (daemon) from within Django
我有一个工作线程,它的唯一任务是每 10 分钟从数据库中查询一次活动用户列表,并在满足特定条件(每分钟检查一次)时向他们发送一条 SMS 消息;工作线程也根本不妨碍主应用程序。
到目前为止,我设法启动了线程,运行发送 SMS 也能正常工作。但是,由于某些原因,线程 stops/gets 在某个随机时间(小时)后终止。我 运行 尝试:except Exception as e: within a while True,以捕获发生的错误。此外,我打印出一条消息,说明发生了什么错误。
好吧,我从来没有看到任何消息,线程肯定已关闭。因此,我怀疑 Gunicorn 或 Django 会优雅地杀死我的线程。
我已经在代码中放置了日志和打印语句,但没有发现任何表明我的线程被杀死的原因。
我的 wsgi.py 函数,我在其中调用该函数来启动我的线程
"""
WSGI config for django_web project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_web.settings')
application = get_wsgi_application()
'''
Start background services
Import has to happen after "get_wsgi_application()"; otherwise docker container crashes
'''
try:
from threading import Thread
from timesheet.admin import runWorkmateServices
runWorkmateServices()
except Exception as exp:
print(exp)
从 wsgi.py 中调用的函数。我仔细检查线程是否已启动以避免出现两个 up 和 运行ning.
def runWorkmateServices(request=None):
service_name = 'TimeKeeperWorkMateReminderService'
thread_found = False
for thread in threading.enumerate():
if service_name in thread.name:
thread_found = True
break # Leave loop now
if thread_found:
print(f'Service has already been started: {service_name}')
if request:
messages.add_message(request, messages.ERROR, f'Service has already been started:: {service_name}')
else:
Thread(target=WorkMateReminders, args=(), name=service_name, daemon=True).start()
print(f'Started Service: {service_name}')
if request:
messages.add_message(request, messages.SUCCESS, f'Started Service: {service_name}')
工作线程本身
def WorkMateReminders():
print('Thread Started: WorkMateReminders')
timer = 0
employees = User.objects.none()
while True:
try:
# Update user list every n * sleep time (10 minutes)
if timer % 10 == 0:
timer = 0
# Get active employees
employees = User.objects.filter(is_active=True, profile__workmate_sms_reminders_activated=True)
print(f'Employees updated at {datetime.now().date()} - {datetime.now().time()}: {employees}')
WorkMateCheckClockOffTimes(employees=employees)
WorkMateClockOnReminder(employees=employees)
WorkMateEndOfBreakReminder(employees=employees)
timer += 1 # increment timer
except Exception as exp:
print(f'Error: {exp}')
time.sleep(60 * 1)
我的目标是只要 Django 启动就让这个工作线程 运行ning。
大多数 WSGI 服务器会相当定期地 killed/recycled 产生工作线程,从这些工作线程产生线程并不是解决您问题的最佳方法。有几种方法可以解决这个问题
Cron
Create a management command that does what you want and configure cron 到 运行 每 10 分钟一次
Celery/Celerybeat
设置一个celery worker, this is a process that runs asynchronously to your Django application and using celerybeat你可以有任务运行间隔
我有一个工作线程,它的唯一任务是每 10 分钟从数据库中查询一次活动用户列表,并在满足特定条件(每分钟检查一次)时向他们发送一条 SMS 消息;工作线程也根本不妨碍主应用程序。
到目前为止,我设法启动了线程,运行发送 SMS 也能正常工作。但是,由于某些原因,线程 stops/gets 在某个随机时间(小时)后终止。我 运行 尝试:except Exception as e: within a while True,以捕获发生的错误。此外,我打印出一条消息,说明发生了什么错误。
好吧,我从来没有看到任何消息,线程肯定已关闭。因此,我怀疑 Gunicorn 或 Django 会优雅地杀死我的线程。
我已经在代码中放置了日志和打印语句,但没有发现任何表明我的线程被杀死的原因。
我的 wsgi.py 函数,我在其中调用该函数来启动我的线程
"""
WSGI config for django_web project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_web.settings')
application = get_wsgi_application()
'''
Start background services
Import has to happen after "get_wsgi_application()"; otherwise docker container crashes
'''
try:
from threading import Thread
from timesheet.admin import runWorkmateServices
runWorkmateServices()
except Exception as exp:
print(exp)
从 wsgi.py 中调用的函数。我仔细检查线程是否已启动以避免出现两个 up 和 运行ning.
def runWorkmateServices(request=None):
service_name = 'TimeKeeperWorkMateReminderService'
thread_found = False
for thread in threading.enumerate():
if service_name in thread.name:
thread_found = True
break # Leave loop now
if thread_found:
print(f'Service has already been started: {service_name}')
if request:
messages.add_message(request, messages.ERROR, f'Service has already been started:: {service_name}')
else:
Thread(target=WorkMateReminders, args=(), name=service_name, daemon=True).start()
print(f'Started Service: {service_name}')
if request:
messages.add_message(request, messages.SUCCESS, f'Started Service: {service_name}')
工作线程本身
def WorkMateReminders():
print('Thread Started: WorkMateReminders')
timer = 0
employees = User.objects.none()
while True:
try:
# Update user list every n * sleep time (10 minutes)
if timer % 10 == 0:
timer = 0
# Get active employees
employees = User.objects.filter(is_active=True, profile__workmate_sms_reminders_activated=True)
print(f'Employees updated at {datetime.now().date()} - {datetime.now().time()}: {employees}')
WorkMateCheckClockOffTimes(employees=employees)
WorkMateClockOnReminder(employees=employees)
WorkMateEndOfBreakReminder(employees=employees)
timer += 1 # increment timer
except Exception as exp:
print(f'Error: {exp}')
time.sleep(60 * 1)
我的目标是只要 Django 启动就让这个工作线程 运行ning。
大多数 WSGI 服务器会相当定期地 killed/recycled 产生工作线程,从这些工作线程产生线程并不是解决您问题的最佳方法。有几种方法可以解决这个问题
Cron
Create a management command that does what you want and configure cron 到 运行 每 10 分钟一次
Celery/Celerybeat
设置一个celery worker, this is a process that runs asynchronously to your Django application and using celerybeat你可以有任务运行间隔