У меня есть Python script, работающий с Django для базы данных и memcache, но он, в частности, запускается как автономный демон (т.е. не отвечает на запросы веб-серверов). Демон проверяет заявку на модель Django для объектов с status=STATUS_NEW
, а затем отмечает их STATUS_WORKING и помещает их в очередь.
Ряд процессов (созданных с использованием пакета многопроцессорности) вытащит вещи из очереди и будет работать над реквизитом с pr.id
, который был передан в очередь. Я полагаю, что утечка памяти, вероятно, находится в следующем коде (но она может быть в коде "Worker" на другой стороне очереди, хотя это маловероятно, потому что поскольку размер памяти растет, даже когда никаких заявок не возникает, т.е. когда все рабочие блокируются на Queue.get()).
from requisitions.models import Requisition # our Django model
from multiprocessing import Queue
while True:
# Wait for "N"ew requisitions, then pop them into the queue.
for pr in Requisition.objects.all().filter(status=Requisition.STATUS_NEW):
pr.set_status(pr.STATUS_WORKING)
pr.save()
queue.put(pr.id)
time.sleep(settings.DAEMON_POLL_WAIT)
Где settings.DAEMON_POLL_WAIT=0.01
.
Кажется, если я оставлю это в течение определенного периода времени (т.е. через пару дней), процесс Python будет расти до бесконечного размера и, в конечном итоге, в системе будет нехватка памяти.
Что происходит здесь (или как я могу узнать), и что еще более важно - как вы можете запустить демон, который делает это?
Моя первая мысль - изменить динамику функции, в частности, поместив проверку на новые объекты заявки в django.core.cache cache
, т.е.
from django.core.cache import cache
while True:
time.sleep(settings.DAEMON_POLL_WAIT)
if cache.get('new_requisitions'):
# Possible race condition
cache.clear()
process_new_requisitions(queue)
def process_new_requisitions(queue):
for pr in Requisition.objects.all().filter(status=Requisition.STATUS_NEW):
pr.set_status(pr.STATUS_WORKING)
pr.save()
queue.put(pr.id)
Процесс создания Requisitions с status=STATUS_NEW
может выполнить cache.set('new_requisitions', 1)
(или, альтернативно, мы могли бы поймать сигнал или событие Requisition.save(), когда создается новое Требование, а затем установите флаг в кеше).
Однако я не уверен, что решение, которое я предложил здесь, касается проблем с памятью (которые, вероятно, связаны с сборкой мусора), поэтому обзор с помощью process_new_requisitions
может решить проблему).
Я благодарен за любые мысли и отзывы.