Состояние гонки в Джанго - PullRequest
0 голосов
/ 17 марта 2011

В Джанго я столкнулся с серьезным состоянием гонки.Проблема начинается, когда два бегуна пытаются выполнить 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 не подходит для этого решения.

1 Ответ

0 голосов
/ 30 июня 2011

Проблема была исправлена ​​путем ручного обновления транзакции. Похоже, что QuerySet не обновлялся с начала транзакции. Когда два QuerySets каким-то образом запускаются одновременно, и в обоих QuerySets происходит одно задание, это приводит к разбивке бегунов.

Прочитав этот ответ , я пришел к решению: как раз перед return True транзакция фиксируется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...