Немного фона:Python синхронизации между потоками и процессами
Я пишу функцию в Django, чтобы получить следующий номер счета, который должен быть последовательным (не пробелы), поэтому функция выглядит следующим образом:
def get_next_invoice_number():
"""
Returns the max(invoice_number) + 1 from the payment records
Does NOT pre-allocate number
"""
# TODO ensure this is thread safe
max_num = Payment.objects.aggregate(Max('invoice_number'))['invoice_number__max']
if max_num is not None:
return max_num + 1
return PaymentConfig.min_invoice_number
Теперь проблема, эта функция только возвращает max()+1
, в моей среде у меня есть несколько процессов Django, поэтому, если эта функция вызывается дважды для 2-х различных платежей (до первой записи сохранены), они получат тот же номер счета-фактуры.
Чтобы устранить эту проблему, я могу переопределить функцию save()
, чтобы вызвать get_next_invoice_number()
, чтобы свести к минимуму промежуток времени между этими вызовами функций, но по-прежнему существует очень малая вероятность возникновения проблемы.
Так что я хочу осуществить блокировку в методе одобрять, что-то вроде
from multiprocessing import Lock
lock = Lock()
class Payment(models.Model):
def approve(self):
lock.acquire()
try:
self.invoice_number = get_next_invoice_number()
self.save()
except:
pass
finally:
lock.release()
Так что мои вопросы:
- ли это выглядеть хорошо?
- Замок предназначен для многопроцессорности, как насчет потоков?
UPDATE:
- Как мой коллега отметил, что это не будет работать, когда он развернут на нескольких серверах, замки не будут иметь смысла.
- Похоже, что блокировка транзакций БД - это путь.
1.) Почему это должно быть последовательным? 2.) Почему вы не можете предварительно идентифицировать идентификатор счета на чеке (т. Е. Используя функцию автоматического прироста DB)? Никаких дубликатов. – Andy
@ Andy это требование бухгалтерского учета для номера счета-фактуры, которое будет последовательным. –