возможное состояние гонки Джанго - PullRequest
0 голосов
/ 29 мая 2018
@receiver(post_save, sender=MyRequestLog)
def steptwo_launcher(sender, instance, **kwargs):
    GeneralLogging(calledBy='MyRequestLog', logmsg='enter steptwo_launcher').save()  # remember to remove this line
    if instance.stepCode == 100:
       GeneralLogging(calledBy='MyRequestLog', logmsg='step code 100 found. launch next step').save()
       nextStep.delay(instance.requestId,False)

Я думаю, я просто стал свидетелем того, как мой код потерял условие гонки.Серверная часть моего приложения обновляет статус задачи 1 и записывает в журнал пошаговый код 100, когда должна быть запущена следующая задача.Внешний интерфейс приложения опрашивает, чтобы сообщить о текущем шаге конечному пользователю.

Похоже, что после того, как бэкэнд создал запись с stepCode 100, фронтальный запрос поступил так скоро после этого, что экземпляр if.stepCode == 100: никогда не было установлено, что это правда.GeneralLogging сообщает только об одной записи во время предполагаемого столкновения и не запускает шаг nextstep.

Мой вопрос 1) Подтвердите, что это возможно, что я уже подозреваю.и 2) способ исправить это, чтобы nextStep не пропускался из-за состояния гонки.

1 Ответ

0 голосов
/ 29 мая 2018

В этом вопросе отсутствует куча потенциально полезной информации (например, отсутствует код, отсутствует вывод), но любой код вида

if state == x:
    change_state

имеет потенциальное состояние гонки, когда несколько путей управления попадают в этот код.

Двумя наиболее распространенными способами решения этой проблемы являются (1) блокировки:

with some_lock:
    if state:
        change_state

то есть не позволяют всем другим использовать этот код, пока мы не закончим, и (2) очереди:

queue.push(item_to_be_processed)

# somewhere else
item_to_be_processed = queue.pop()

Реализация очереди / блокировки в БД может использовать select_for_update и использовать дополнительное поле processed, т. Е. Позволить процессу «записи» сохранить модель с помощью processed = False и иметь «читатель»"process do:

from django.db import transaction
...
with transaction.atomic():
    items = MyRequestLog.objects.select_for_update(skip_locked=True).filter(
        stepCode=100, 
        processed=False
    )
    for item in items:
        do_something_useful(item)  # you might want to pull this outside of the atomic block if your application allows (so you don't keep rows locked for an extended period)
        item.processed = True
        item.save()

ps: проверьте вашу базу данных на предмет поддержки (https://docs.djangoproject.com/en/2.0/ref/models/querysets/#select-for-update)

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