Дублирующиеся потоки запросов создают повторяющиеся записи базы данных в модели Django.

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

В функции приемника:

try:
    my_instance = MyModel.objects.get(field1=value1, field2=sender)
except:
    my_instance = MyModel(field1=value1, field2=sender)
    my_instance.save()

Это очевидный кандидат на get_or_create, но помимо очистки этого кода, поможет ли использование get_or_create предотвратить эту проблему?

Сигнал отправляется после действия пользователя, но я не верю, что исходный запрос дублируется, потому что это вызвало бы другие действия.

Дублирование произошло несколько раз в тысячах случаев. Это обязательно вызвано несколькими запросами или можно каким-то образом создать повторяющийся поток? И есть ли способ — возможно, с детальным управлением транзакциями — предотвратить дублирование?

Использование Django 1.1, Python 2.4, PostgreSQL 8.1 и mod_wsgi на Apache2.


person bennylope    schedule 11.03.2011    source источник
comment
Удаление моего ответа, так как я не обращаюсь к безопасности потоков. Просто отметим, что с вашей настройкой, если MyModel когда-либо получит дубликат, созданный любым способом, он будет постоянно создавать дубликаты, когда get возвращает исключение MultipleObjectsReturned.   -  person Yuji 'Tomita' Tomita    schedule 12.03.2011


Ответы (2)


чтобы предотвратить дублирование сигналов, добавьте параметр «dispatch_uid» в код подключения сигнала как описано в документах.

убедитесь, что у вас открыта транзакция - иначе может случиться так, что между проверкой (objects.get()) и созданием (save()) состояние таблицы изменится.

person Jerzyk    schedule 11.03.2011
comment
Удивительно - не знаю почему, но этого нет в документации Django 1.1, хотя он определенно есть в модуле отправки Django 1.1. Собираюсь попробовать это. - person bennylope; 12.03.2011

Возможно, этот ответ может помощь. По-видимому, транзакция правильно используется с get_or_create, но я этого не подтверждал. mod_wsgi является многопроцессорным и многопоточным (оба настраиваются), а это означает, что условия гонки определенно могут возникнуть. Я предполагаю, что в вашем приложении происходит то, что запускаются два отдельных запроса, которые будут генерировать одно и то же значение для field1, и так уж получилось, что они выполняются с правильным временем для добавления «дубликатов» записей.

Если комбинация MyModel(field1=value1, field2=sender) должна быть уникальной, то определите ограничение unique_together для вашей модели, чтобы дополнительно способствовать целостности.

person Josh Smeaton    schedule 11.03.2011
comment
Спасибо за напоминание. Да, ограничение решило бы конечную проблему и было бы хорошей идеей для общей целостности данных, но, конечно, хотелось бы избежать изменения рабочей базы данных, если этого можно избежать. - person bennylope; 12.03.2011
comment
@benny, понятно, но если ограничение действует на уровне данных, то его следует применить. Ошибки в модели данных должны быть исправлены как можно скорее. Тем не менее, get_or_create должен служить вашим целям в то же время с использованием транзакции. - person Josh Smeaton; 12.03.2011