Сигналы Django 1.1 - странная проблема синхронизации с потоком

У меня есть модель (PurchaseOrder — сокращенно PO), содержащая временной бюджет. Пользователи могут добавлять записи часов в этот бюджет, где каждая запись часов уменьшает оставшийся бюджет.

Я реализовал сигналы для обновления остатка бюджета. После добавления часовой записи бюджет соответственно уменьшается. Поскольку вычисление потенциально требует много времени, я использовал для этой задачи поток.

def update_po_remaining_value(sender, instance, **kwargs):
    CalculatePOThread(sender, instance).start()   
post_save.connect(update_po_remaining_value, sender=HourRecord)       
post_delete.connect(update_po_remaining_value, sender=HourRecord) 

Поток CalculatePOThread вычисляет оставшееся значение бюджета PO, получая набор часовых записей и вычитая общий часовой набор записей из бюджета.

hr_set = HourRecord.objects.filter(purchase_order = po)

В моем dev.workspace это работает отлично. В рабочей среде соединение post_save также работает нормально, но у меня возникла странная проблема с сигналом post_delete. Довольно часто бывает так, что сумма часовых записей, возвращаемая запросом HourRecord.objects.filter(purchase_order = po), по-прежнему включает удаленную часовую запись, которая инициировала поток CalculatePOThread.

Во всяком случае, я обошел это поведение, добавив в поток 6-секундную задержку перед выполнением запроса. время сна (6).

Кто-нибудь знает, почему может возникнуть такая ситуация? похоже, что сигнал post_delete срабатывает до того, как запись действительно удаляется из базы данных..!? Но это будет ошибка в Django, и это будет мое последнее предположение.


person Thomas Kremmel    schedule 07.05.2012    source источник


Ответы (1)


Трудно сказать, но я предполагаю, что вы столкнулись с проблемой безопасности потоков. Когда вы создаете поток для обработки длительной задачи, вы должны знать, что, пока он пытается завершиться, аналогичный поток может быть легко запущен с той же задачей. Как правило, при работе с потоками вы хотите свести их след к минимуму или, другими словами, не делать их сильно зависимыми от состояния базы данных и тому подобного.

Если доступ к базе данных требуется, как в данном случае, вам необходимо установить блокировки, чтобы предотвратить одновременное вмешательство в базу данных. Однако это будет намного сложнее, учитывая, что вы используете Django 1.1. Как добиться блокировки на уровне таблицы в Django 1.1 будет зависеть от сервера базы данных, на котором вы работаете, и требует отдельного вопроса.

person Chris Pratt    schedule 07.05.2012
comment
Спасибо за Ваш ответ. Еще одна информация: я убедился, что я единственный, кто возится с prod.env. и срабатывает просто по одному - сигнал post.delete. Поэтому я заверил, что никакие другие потоки не конфликтуют с моими тестами. Таким образом, блокировка должна быть установлена ​​командой удаления объекта, а сигнал post_delete должен срабатывать только после снятия блокировки / удаления объекта. Но это внутренние дела Django, на которые я, наверное, не могу повлиять. PS: БД = postgres, веб-сервер = apache. - person Thomas Kremmel; 08.05.2012
comment
похоже, что эта проблема также обсуждается здесь: groups.google .com/group/django-haystack/browse_thread/thread/ - person Thomas Kremmel; 08.05.2012