У меня есть сценарий Python, выполняющий Django для базы данных и memcache, но он заметно работает как автономный демон (то есть не отвечает на запросы веб-сервера). Демон проверяет реквизицию модели Django для объектов с status=STATUS_NEW
, затем помечает их как STATUS_WORKING и помещает их в очередь.
Ряд процессов (созданных с использованием многопроцессорного пакета) извлекают данные из очереди и выполняют работу над заявкой с pr.id
, который был передан в очередь. Я полагаю, что утечка памяти, вероятно, заключается в следующем коде (но это может быть в «рабочем» коде на другой стороне очереди, хотя это маловероятно, потому что размер памяти увеличивается, даже когда не появляются никакие реквизиты - т.е. когда все работники блокируют 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)
Процесс, который создает реквизиты с помощью status=STATUS_NEW
, может сделать cache.set('new_requisitions', 1)
(или, в качестве альтернативы, мы можем перехватить сигнал или событие Requisition.save (), где создается новая заявка, и затем установить флаг в кеше ).
Однако я не уверен, что предложенное мной решение направлено на решение проблем с памятью (которые, вероятно, связаны со сборкой мусора, поэтому проблема может быть решена с помощью process_new_requisitions
).
Я благодарен за любые мысли и отзывы.