В Django я столкнулся с серьезным состоянием гонки. Проблема начинается, когда два участника пытаются одновременно выполнить some_method (). Журнал создается следующим образом:
Job 3: Candidate
Job 3: Already taken
Job 3: Candidate
Job 3: Already taken
Job 3: Candidate
Job 3: Already taken
(et cetera for 18 MB)
Следующий метод вызывает у меня проблемы. Следует отметить, что метод запускается повторно до тех пор, пока метод не вернет False
:
def some_method():
conditions = #(amongst others, excludes jobs with status EXECUTING)
try:
cjob = Job.objects.filter(conditions).order_by(some_fields)[0]
except IndexError:
return False
print 'Job %s: Candidate' % cjob.id
job = cjob.for_update()
if cjob.status != job.status:
print 'Job %s: Already taken' % cjob.id
return True
print 'Job %s: Starting...' % job.id
job.status = Job.EXECUTING
job.save()
# Critical section
# In models.py:
class Job(models.Model):
# ...
def for_update(self):
return Job.objects.raw('SELECT * FROM `backend_job` WHERE `id` = %s FOR UPDATE', (self.id, ))[0]
В настоящее время Django не имеет специального метода for_update, и для предотвращения создания запроса со всеми условиями, которые мы используем для определения необходимости выполнения задания, мы выполняем сложный запрос перед простым запросом FOR UPDATE.
Я действительно не понимаю, как это могло вызвать проблемы, которые мы видим, мы выполняем запрос, за которым следует инструкция, которая блокирует, когда другой бегун удерживает блокировку на задании. Блокировка снимается только после изменения статуса задания. Второй бегун теперь получает блокировку, но статус задания был изменен, поэтому он возвращается из метода только для того, чтобы повторно войти в него позже; но cjob
-запрос больше не вернет то же задание, так как его статус теперь исключен фильтром.
Неправильно ли я истолковал предложение FOR UPDATE или я упустил что-то еще?
Следует отметить, что я использую MySQL с InnoDB и что Celery не подходит для этого решения.
job.status
иcjob.status
? Какие бывают типы? - person dappawit   schedule 18.03.2011